Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@

import static io.f1.backend.domain.quiz.mapper.QuizMapper.toGameStartResponse;

import io.f1.backend.domain.game.dto.request.GameStartRequest;
import io.f1.backend.domain.game.dto.response.GameStartResponse;
import io.f1.backend.domain.game.event.RoomUpdatedEvent;
import io.f1.backend.domain.game.model.GameSetting;
import io.f1.backend.domain.game.model.Player;
import io.f1.backend.domain.game.model.Room;
import io.f1.backend.domain.game.model.RoomState;
import io.f1.backend.domain.game.store.RoomRepository;
import io.f1.backend.domain.question.entity.Question;
import io.f1.backend.domain.quiz.app.QuizService;
import io.f1.backend.domain.quiz.entity.Quiz;
import io.f1.backend.domain.user.dto.UserPrincipal;
import io.f1.backend.global.exception.CustomException;
import io.f1.backend.global.exception.errorcode.GameErrorCode;
import io.f1.backend.global.exception.errorcode.RoomErrorCode;
Expand All @@ -24,6 +23,7 @@

import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
@RequiredArgsConstructor
Expand All @@ -33,53 +33,54 @@ public class GameService {
private final RoomRepository roomRepository;
private final ApplicationEventPublisher eventPublisher;

public GameStartResponse gameStart(Long roomId, GameStartRequest gameStartRequest) {

Long quizId = gameStartRequest.quizId();
public GameStartResponse gameStart(Long roomId, UserPrincipal principal) {

Room room =
roomRepository
.findRoom(roomId)
.orElseThrow(() -> new CustomException(RoomErrorCode.ROOM_NOT_FOUND));

if (!validateReadyStatus(room)) {
throw new CustomException(RoomErrorCode.PLAYER_NOT_READY);
}

// 방의 gameSetting에 설정된 퀴즈랑 요청 퀴즈랑 같은지 체크 후 GameSetting에서 라운드 가져오기
Integer round = checkGameSetting(room, quizId);
validateRoomStart(room, principal);

Long quizId = room.getGameSetting().getQuizId();
Quiz quiz = quizService.getQuizWithQuestionsById(quizId);
List<Question> questions = prepareQuestions(room, quiz);

// 라운드 수만큼 랜덤 Question 추출
List<Question> questions = quizService.getRandomQuestionsWithoutAnswer(quizId, round);
room.updateQuestions(questions);

GameStartResponse gameStartResponse = toGameStartResponse(questions);

// 방 정보 게임 중으로 변경
room.updateRoomState(RoomState.PLAYING);

eventPublisher.publishEvent(new RoomUpdatedEvent(room, quiz));

return gameStartResponse;
return toGameStartResponse(questions);
}

private Integer checkGameSetting(Room room, Long quizId) {

GameSetting gameSetting = room.getGameSetting();
private boolean validateReadyStatus(Room room) {

if (!gameSetting.validateQuizId(quizId)) {
throw new CustomException(GameErrorCode.GAME_SETTING_CONFLICT);
}
Map<String, Player> playerSessionMap = room.getPlayerSessionMap();

return gameSetting.getRound();
return playerSessionMap.values().stream().allMatch(Player::isReady);
}

private boolean validateReadyStatus(Room room) {
private void validateRoomStart(Room room, UserPrincipal principal) {
if (!Objects.equals(principal.getUserId(), room.getHost().getId())) {
throw new CustomException(RoomErrorCode.NOT_ROOM_OWNER);
}

Map<String, Player> playerSessionMap = room.getPlayerSessionMap();
if (!validateReadyStatus(room)) {
throw new CustomException(GameErrorCode.PLAYER_NOT_READY);
}

return playerSessionMap.values().stream().allMatch(Player::isReady);
if (room.getState() == RoomState.PLAYING) {
throw new CustomException(RoomErrorCode.GAME_ALREADY_PLAYING);
}
}

// 라운드 수만큼 랜덤 Question 추출
private List<Question> prepareQuestions(Room room, Quiz quiz) {
Long quizId = quiz.getId();
Integer round = room.getGameSetting().getRound();
return quizService.getRandomQuestionsWithoutAnswer(quizId, round);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package io.f1.backend.domain.game.websocket;

import static io.f1.backend.domain.game.websocket.WebSocketUtils.getSessionId;
import static io.f1.backend.domain.game.websocket.WebSocketUtils.getSessionUser;

import io.f1.backend.domain.game.app.GameService;
import io.f1.backend.domain.game.app.RoomService;
import io.f1.backend.domain.game.dto.ChatMessage;
Expand All @@ -8,7 +11,6 @@
import io.f1.backend.domain.game.dto.RoomInitialData;
import io.f1.backend.domain.game.dto.RoundResult;
import io.f1.backend.domain.game.dto.request.DefaultWebSocketRequest;
import io.f1.backend.domain.game.dto.request.GameStartRequest;
import io.f1.backend.domain.game.dto.response.GameStartResponse;
import io.f1.backend.domain.game.dto.response.PlayerListResponse;
import io.f1.backend.domain.user.dto.UserPrincipal;
Expand All @@ -18,8 +20,6 @@
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;

@Controller
Expand Down Expand Up @@ -71,12 +71,11 @@ public void exitRoom(@DestinationVariable Long roomId, Message<?> message) {
}

@MessageMapping("/room/start/{roomId}")
public void gameStart(
@DestinationVariable Long roomId,
Message<DefaultWebSocketRequest<GameStartRequest>> message) {
public void gameStart(@DestinationVariable Long roomId, Message<?> message) {

UserPrincipal principal = getSessionUser(message);

GameStartResponse gameStartResponse =
gameService.gameStart(roomId, message.getPayload().getMessage());
GameStartResponse gameStartResponse = gameService.gameStart(roomId, principal);

String destination = getDestination(roomId);

Expand Down Expand Up @@ -112,17 +111,6 @@ public void playerReady(@DestinationVariable Long roomId, Message<?> message) {
messageSender.send(getDestination(roomId), MessageType.PLAYER_LIST, playerListResponse);
}

private static String getSessionId(Message<?> message) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
return accessor.getSessionId();
}

private static UserPrincipal getSessionUser(Message<?> message) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
Authentication auth = (Authentication) accessor.getUser();
return (UserPrincipal) auth.getPrincipal();
}

private String getDestination(Long roomId) {
return "/sub/room/" + roomId;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.f1.backend.domain.game.websocket;

import io.f1.backend.domain.user.dto.UserPrincipal;

import org.springframework.messaging.Message;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.security.core.Authentication;

public class WebSocketUtils {

public static String getSessionId(Message<?> message) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
return accessor.getSessionId();
}

public static UserPrincipal getSessionUser(Message<?> message) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
Authentication auth = (Authentication) accessor.getUser();
return (UserPrincipal) auth.getPrincipal();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
@Getter
@RequiredArgsConstructor
public enum GameErrorCode implements ErrorCode {
GAME_SETTING_CONFLICT("E409002", HttpStatus.CONFLICT, "게임 설정이 맞지 않습니다.");
GAME_SETTING_CONFLICT("E409002", HttpStatus.CONFLICT, "게임 설정이 맞지 않습니다."),
PLAYER_NOT_READY("E403004", HttpStatus.FORBIDDEN, "게임 시작을 위한 준비 상태가 아닙니다.");

private final String code;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
public enum RoomErrorCode implements ErrorCode {
ROOM_USER_LIMIT_REACHED("E403002", HttpStatus.FORBIDDEN, "정원이 모두 찼습니다."),
ROOM_GAME_IN_PROGRESS("E403003", HttpStatus.FORBIDDEN, "게임이 진행 중 입니다."),
PLAYER_NOT_READY("E403004", HttpStatus.FORBIDDEN, "게임 시작을 위한 준비 상태가 아닙니다."),
ROOM_NOT_FOUND("E404005", HttpStatus.NOT_FOUND, "존재하지 않는 방입니다."),
WRONG_PASSWORD("E401006", HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지않습니다."),
PLAYER_NOT_FOUND("E404007", HttpStatus.NOT_FOUND, "존재하지 않는 플레이어입니다."),
SOCKET_SESSION_NOT_FOUND("E404006", HttpStatus.NOT_FOUND, "존재하지 않는 소켓 세션입니다.");
SOCKET_SESSION_NOT_FOUND("E404006", HttpStatus.NOT_FOUND, "존재하지 않는 소켓 세션입니다."),
GAME_ALREADY_PLAYING("E400015", HttpStatus.BAD_REQUEST, "이미 게임이 진행 중 입니다."),
NOT_ROOM_OWNER("E403005", HttpStatus.FORBIDDEN, "방장만 게임 시작이 가능합니다.");

private final String code;

Expand Down