diff --git a/src/main/java/game/single/service/SingleGameServiceImpl.java b/src/main/java/game/single/service/SingleGameServiceImpl.java index 0b78fa9..c8c4b99 100644 --- a/src/main/java/game/single/service/SingleGameServiceImpl.java +++ b/src/main/java/game/single/service/SingleGameServiceImpl.java @@ -49,7 +49,11 @@ public SingleGameServiceImpl(String roomId, ScheduledExecutorService scheduler) @Override public synchronized void onOpen(Session session, String userId) throws Exception { + System.out.println("[SingleGame] onOpen - roomId=" + roomId + " userId=" + userId + + " currentPlayers=" + players.size() + " sessionId=" + session.getId()); + if (players.size() >= 2) { + System.out.println("[SingleGame] REJECT - 이미 2명이 접속중입니다."); session.close(); return; } @@ -58,7 +62,7 @@ public synchronized void onOpen(Session session, String userId) throws Exception players.add(session); sessionToUserId.put(session, userId); - System.out.println("접속: " + session.getId()); + System.out.println("[SingleGame] 접속 완료: " + session.getId() + " (현재 " + players.size() + "명)"); // 2) 아직 2명 안 찼으면 WAIT 브로드캐스트 if (players.size() < 2) { @@ -96,9 +100,14 @@ public synchronized void onOpen(Session session, String userId) throws Exception @Override public synchronized void onMessage(String msg, Session session) throws Exception { - if (gameOver.get()) + System.out.println("[SingleGame] onMessage - msg=" + msg + " sessionId=" + session.getId() + + " gameOver=" + gameOver.get() + " turn=" + turn.get() + " players.size=" + players.size()); + + if (gameOver.get()) { + System.out.println("[SingleGame] 게임이 이미 종료됨 - 메시지 무시"); return; - + } + JsonObject json = gson.fromJson(msg, JsonObject.class); if (msg.contains("SINGLE_GIVEUP")) { @@ -125,8 +134,17 @@ public synchronized void onMessage(String msg, Session session) throws Exception return; } - if (players.get(turn.get()) != session) + int currentTurnIdx = turn.get(); + Session currentTurnSession = (currentTurnIdx < players.size()) ? players.get(currentTurnIdx) : null; + System.out.println("[SingleGame] 턴 체크 - currentTurnIdx=" + currentTurnIdx + + " currentTurnSession=" + (currentTurnSession != null ? currentTurnSession.getId() : "null") + + " requestSession=" + session.getId() + + " isSame=" + (currentTurnSession == session)); + + if (players.get(turn.get()) != session) { + System.out.println("[SingleGame] 턴이 아닌 플레이어의 요청 - 무시"); return; + } if (!json.has("x") || !json.has("y")) { return; @@ -182,11 +200,15 @@ public synchronized void onMessage(String msg, Session session) throws Exception @Override public synchronized void onClose(Session session) { + System.out.println("[SingleGame] onClose - sessionId=" + session.getId() + + " currentPlayers=" + players.size()); + players.remove(session); sessionToUserId.remove(session); // 남은 사람이 없으면 게임 리셋(혹은 게임 종료 처리) if (players.isEmpty()) { + System.out.println("[SingleGame] 모든 플레이어 나감 - 게임 리셋"); board = new int[15][15]; turn.set(0); gameOver.set(false); @@ -194,7 +216,7 @@ public synchronized void onClose(Session session) { wpass = 0; if (turnTask != null) turnTask.cancel(false); } - System.out.println("연결 종료: " + session.getId()); + System.out.println("[SingleGame] 연결 종료 완료: " + session.getId() + " (남은 플레이어: " + players.size() + "명)"); } private synchronized void startTurnTimer() { diff --git a/src/main/java/room/service/RoomService.java b/src/main/java/room/service/RoomService.java index e1e663c..7f341bf 100644 --- a/src/main/java/room/service/RoomService.java +++ b/src/main/java/room/service/RoomService.java @@ -10,6 +10,7 @@ public class RoomService { private static final String STATUS_IN_ROOM = "0"; private static final String STATUS_EXIT = "2"; + private static final String DELETED_ROOM_ID = "00000000-0000-0000-0000-000000000000"; /** * @return 결과 상태 @@ -72,6 +73,12 @@ SELECT COUNT(*) AS cnt AND host_user_id = ? """; + final String qUpdateGameResultRoomId = """ + UPDATE game_result + SET room_id = ? + WHERE room_id = ? + """; + final String qDeleteRoomPlayers = """ DELETE FROM room_player WHERE room_id = ? @@ -87,14 +94,21 @@ SELECT COUNT(*) AS cnt try { // 방 row 잠금 + boolean roomExists = false; try (PreparedStatement pstmt = conn.prepareStatement(qLockRoom)) { pstmt.setString(1, roomId); try (ResultSet rs = pstmt.executeQuery()) { - if (!rs.next()) - throw new IllegalArgumentException("room not found: " + roomId); + roomExists = rs.next(); } } + // 방이 이미 삭제되었으면 조용히 종료 (정상 처리) + if (!roomExists) { + System.out.println("[RoomService] 방이 이미 삭제됨 - roomId=" + roomId); + conn.commit(); + return "ROOM_DELETE"; + } + // 퇴장 처리 (IN_ROOM -> EXIT) int updated; try (PreparedStatement pstmt = conn.prepareStatement(qExitPlayer)) { @@ -105,8 +119,11 @@ SELECT COUNT(*) AS cnt updated = pstmt.executeUpdate(); } + System.out.println("[RoomService] 퇴장 처리 - roomId=" + roomId + " userId=" + userId + " updated=" + updated); + // 이미 나가있거나 없는 유저면 아무 것도 안 함 if (updated == 0) { + System.out.println("[RoomService] 이미 나간 유저 - 종료"); conn.commit(); return "ROOM_EXIT"; } @@ -128,18 +145,32 @@ SELECT COUNT(*) AS cnt } } + System.out.println("[RoomService] 남은 인원 - roomId=" + roomId + " activeCnt=" + activeCnt); + // 방에 아무도 없으면 방 삭제 if (activeCnt == 0) { + // 1) game_result의 room_id를 특수 값으로 변경 (외래 키 제약 조건 회피) + try (PreparedStatement pstmt = conn.prepareStatement(qUpdateGameResultRoomId)) { + pstmt.setString(1, DELETED_ROOM_ID); + pstmt.setString(2, roomId); + int gameResultUpdated = pstmt.executeUpdate(); + System.out.println("[RoomService] game_result의 room_id 업데이트: " + gameResultUpdated + "건"); + } + + // 2) room_player 삭제 try (PreparedStatement pstmt = conn.prepareStatement(qDeleteRoomPlayers)) { pstmt.setString(1, roomId); pstmt.executeUpdate(); } + + // 3) room 삭제 try (PreparedStatement pstmt = conn.prepareStatement(qDeleteRoom)) { pstmt.setString(1, roomId); pstmt.executeUpdate(); } conn.commit(); + System.out.println("[RoomService] 방 삭제 완료: " + roomId); return "ROOM_DELETE"; } diff --git a/src/main/resources/db/migration/V7__alter_gameresult.sql b/src/main/resources/db/migration/V7__alter_gameresult.sql new file mode 100644 index 0000000..b3b1b0d --- /dev/null +++ b/src/main/resources/db/migration/V7__alter_gameresult.sql @@ -0,0 +1,2 @@ +ALTER TABLE game_result +DROP CONSTRAINT FK_GAME_RESULT_ROOM; \ No newline at end of file diff --git a/src/main/resources/db/migration/V8__insert_room.sql b/src/main/resources/db/migration/V8__insert_room.sql new file mode 100644 index 0000000..0d1a991 --- /dev/null +++ b/src/main/resources/db/migration/V8__insert_room.sql @@ -0,0 +1,4 @@ +DELETE +FROM room +WHERE id = '00000000-0000-0000-0000-000000000000'; +COMMIT; \ No newline at end of file