274 lines
6.7 KiB
TypeScript
274 lines
6.7 KiB
TypeScript
import { Injectable, Inject, forwardRef } from '@nestjs/common';
|
||
import { PrismaService } from '../prisma/prisma.service';
|
||
import { customAlphabet } from 'nanoid';
|
||
import { RoomEventsService } from '../game/room-events.service';
|
||
import { RoomPackService } from '../room-pack/room-pack.service';
|
||
|
||
const nanoid = customAlphabet('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 6);
|
||
|
||
@Injectable()
|
||
export class RoomsService {
|
||
constructor(
|
||
private prisma: PrismaService,
|
||
@Inject(forwardRef(() => RoomEventsService))
|
||
private roomEventsService: RoomEventsService,
|
||
private roomPackService: RoomPackService,
|
||
) {}
|
||
|
||
async createRoom(hostId: string, questionPackId?: string, settings?: any) {
|
||
const code = nanoid();
|
||
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
|
||
|
||
// Remove undefined values from settings and ensure questionPackId is handled correctly
|
||
const cleanSettings = settings ? { ...settings } : {};
|
||
if ('questionPackId' in cleanSettings) {
|
||
delete cleanSettings.questionPackId;
|
||
}
|
||
|
||
const room = await this.prisma.room.create({
|
||
data: {
|
||
code,
|
||
hostId,
|
||
expiresAt,
|
||
...cleanSettings,
|
||
questionPackId: questionPackId || null,
|
||
},
|
||
include: {
|
||
host: true,
|
||
questionPack: true,
|
||
},
|
||
});
|
||
|
||
await this.prisma.participant.create({
|
||
data: {
|
||
userId: hostId,
|
||
roomId: room.id,
|
||
name: room.host.name || 'Host',
|
||
role: 'HOST',
|
||
},
|
||
});
|
||
|
||
// Create RoomPack (always, even if empty)
|
||
await this.roomPackService.create(room.id, questionPackId);
|
||
|
||
// Return room with roomPack
|
||
return this.getRoomByCode(room.code);
|
||
}
|
||
|
||
async getRoomByCode(code: string) {
|
||
return this.prisma.room.findUnique({
|
||
where: { code },
|
||
include: {
|
||
host: true,
|
||
participants: {
|
||
include: { user: true },
|
||
},
|
||
questionPack: true,
|
||
roomPack: true,
|
||
},
|
||
});
|
||
}
|
||
|
||
async joinRoom(roomId: string, userId: string, name: string, role: 'PLAYER' | 'SPECTATOR') {
|
||
const participant = await this.prisma.participant.create({
|
||
data: {
|
||
userId,
|
||
roomId,
|
||
name,
|
||
role,
|
||
},
|
||
});
|
||
|
||
// Получаем обновленную комнату со всеми участниками
|
||
const room = await this.prisma.room.findUnique({
|
||
where: { id: roomId },
|
||
include: {
|
||
host: true,
|
||
participants: {
|
||
include: { user: true },
|
||
},
|
||
questionPack: true,
|
||
},
|
||
});
|
||
|
||
// Отправляем событие roomUpdate всем клиентам в комнате
|
||
if (room) {
|
||
this.roomEventsService.emitRoomUpdate(room.code, room);
|
||
}
|
||
|
||
return participant;
|
||
}
|
||
|
||
async updateRoomStatus(roomId: string, status: 'WAITING' | 'PLAYING' | 'FINISHED') {
|
||
return this.prisma.room.update({
|
||
where: { id: roomId },
|
||
data: { status },
|
||
});
|
||
}
|
||
|
||
async updateParticipantScore(participantId: string, score: number) {
|
||
return this.prisma.participant.update({
|
||
where: { id: participantId },
|
||
data: { score },
|
||
});
|
||
}
|
||
|
||
async updateQuestionPack(roomId: string, questionPackId: string) {
|
||
return this.prisma.room.update({
|
||
where: { id: roomId },
|
||
data: {
|
||
questionPackId,
|
||
currentQuestionIndex: 0,
|
||
revealedAnswers: {},
|
||
},
|
||
include: {
|
||
host: true,
|
||
participants: {
|
||
include: { user: true },
|
||
},
|
||
questionPack: true,
|
||
},
|
||
});
|
||
}
|
||
|
||
async updateCustomQuestions(roomId: string, questions: any) {
|
||
// DEPRECATED: Use updateRoomPack instead
|
||
return this.updateRoomPack(roomId, questions);
|
||
}
|
||
|
||
async updateRoomPack(roomId: string, questions: any[]) {
|
||
await this.roomPackService.updateQuestions(roomId, questions);
|
||
|
||
const room = await this.prisma.room.findUnique({
|
||
where: { id: roomId },
|
||
include: {
|
||
host: true,
|
||
participants: {
|
||
include: { user: true },
|
||
},
|
||
questionPack: true,
|
||
roomPack: true,
|
||
},
|
||
});
|
||
|
||
this.roomEventsService.emitRoomPackUpdated(room.code, room);
|
||
return room;
|
||
}
|
||
|
||
async getEffectiveQuestions(roomId: string) {
|
||
const room = await this.prisma.room.findUnique({
|
||
where: { id: roomId },
|
||
include: { roomPack: true, questionPack: true },
|
||
});
|
||
|
||
if (!room) {
|
||
return null;
|
||
}
|
||
|
||
// Priority 1: RoomPack questions
|
||
if (room.roomPack && room.roomPack.questions) {
|
||
return room.roomPack.questions;
|
||
}
|
||
|
||
// Priority 2: QuestionPack (fallback for legacy rooms)
|
||
if (room.questionPack) {
|
||
return room.questionPack.questions;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
async updateRoomSettings(roomId: string, settings: any) {
|
||
const room = await this.prisma.room.update({
|
||
where: { id: roomId },
|
||
data: settings,
|
||
include: {
|
||
host: true,
|
||
participants: {
|
||
include: { user: true },
|
||
},
|
||
questionPack: true,
|
||
},
|
||
});
|
||
|
||
this.roomEventsService.emitRoomUpdate(room.code, room);
|
||
return room;
|
||
}
|
||
|
||
async restartGame(roomId: string) {
|
||
await this.prisma.room.update({
|
||
where: { id: roomId },
|
||
data: {
|
||
status: 'WAITING',
|
||
currentQuestionIndex: 0,
|
||
revealedAnswers: {},
|
||
currentPlayerId: null,
|
||
isGameOver: false,
|
||
answeredQuestions: 0,
|
||
},
|
||
});
|
||
|
||
await this.prisma.participant.updateMany({
|
||
where: { roomId },
|
||
data: { score: 0 },
|
||
});
|
||
|
||
const room = await this.prisma.room.findUnique({
|
||
where: { id: roomId },
|
||
include: {
|
||
host: true,
|
||
participants: {
|
||
include: { user: true },
|
||
},
|
||
questionPack: true,
|
||
},
|
||
});
|
||
|
||
if (room) {
|
||
this.roomEventsService.emitGameRestarted(room.code, room);
|
||
}
|
||
|
||
return room;
|
||
}
|
||
|
||
async setCurrentPlayer(roomId: string, playerId: string) {
|
||
const room = await this.prisma.room.update({
|
||
where: { id: roomId },
|
||
data: { currentPlayerId: playerId },
|
||
include: {
|
||
host: true,
|
||
participants: {
|
||
include: { user: true },
|
||
},
|
||
questionPack: true,
|
||
},
|
||
});
|
||
|
||
this.roomEventsService.emitCurrentPlayerChanged(room.code, { playerId });
|
||
return room;
|
||
}
|
||
|
||
async kickPlayer(roomId: string, participantId: string) {
|
||
await this.prisma.participant.update({
|
||
where: { id: participantId },
|
||
data: { isActive: false },
|
||
});
|
||
|
||
const room = await this.prisma.room.findUnique({
|
||
where: { id: roomId },
|
||
include: {
|
||
host: true,
|
||
participants: {
|
||
include: { user: true },
|
||
},
|
||
questionPack: true,
|
||
},
|
||
});
|
||
|
||
if (room) {
|
||
this.roomEventsService.emitPlayerKicked(room.code, { participantId, room });
|
||
}
|
||
|
||
return room;
|
||
}
|
||
}
|