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
32 changes: 27 additions & 5 deletions src/main/java/game/single/service/SingleGameServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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")) {
Expand All @@ -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;
Expand Down Expand Up @@ -182,19 +200,23 @@ 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);
bpass = 0;
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() {
Expand Down
35 changes: 33 additions & 2 deletions src/main/java/room/service/RoomService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

DELETED_ROOM_ID 상수가 데이터베이스에 존재하는 더미 방을 전제로 합니다.

이 상수는 삭제된 방의 게임 결과를 보관하기 위한 플레이스홀더로 사용됩니다. 그러나 V8__insert_room.sql 마이그레이션이 현재 이 UUID의 방을 삭제하고 있어, 실제로는 존재하지 않는 방을 참조하게 됩니다.

V8 마이그레이션을 수정하여 이 UUID로 더미 방을 생성(INSERT)하도록 변경해야 합니다.

🤖 Prompt for AI Agents
In src/main/java/room/service/RoomService.java around line 13, the
DELETED_ROOM_ID constant (00000000-0000-0000-0000-000000000000) assumes a dummy
room exists in the DB but the V8__insert_room.sql migration currently deletes
that UUID; update the V8 migration to INSERT a dummy room row with this exact
UUID (populate required columns such as id, name, created_at, any non-nullable
fields and sensible defaults) so the constant points to a real record, and
ensure the migration runs before code that relies on the constant.


/**
* @return 결과 상태
Expand Down Expand Up @@ -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 = ?
Expand All @@ -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)) {
Expand All @@ -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";
}
Expand All @@ -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";
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/db/migration/V7__alter_gameresult.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE game_result
DROP CONSTRAINT FK_GAME_RESULT_ROOM;
4 changes: 4 additions & 0 deletions src/main/resources/db/migration/V8__insert_room.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DELETE
FROM room
WHERE id = '00000000-0000-0000-0000-000000000000';
COMMIT;
Comment on lines +1 to +4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

마이그레이션 로직이 커밋 메시지 및 의도와 불일치합니다.

커밋 메시지에서는 "삭제된 방의 전적을 보관할 더미 데이터 생성"이라고 명시했지만, 이 마이그레이션은 DELETE 문을 사용하여 해당 UUID의 방을 삭제하고 있습니다.

RoomService.java에서 방 삭제 시 game_result.room_idDELETED_ROOM_ID (동일한 UUID)로 업데이트하는데, 이 마이그레이션이 해당 방을 삭제하면 game_result 레코드들이 존재하지 않는 방을 참조하게 됩니다.

다음 중 하나로 수정이 필요합니다:

  1. DELETE 대신 INSERT 문을 사용하여 더미 방을 생성
  2. 또는 이미 더미 방이 존재한다면, 이 마이그레이션 파일 자체가 불필요
🔎 제안하는 수정 방안
-DELETE
-FROM room
-WHERE id = '00000000-0000-0000-0000-000000000000';
-COMMIT;
+INSERT INTO room (id, host_user_id, current_user_cnt, max_user_cnt, room_name, room_password, created_at)
+VALUES (
+  '00000000-0000-0000-0000-000000000000',
+  '00000000-0000-0000-0000-000000000000',
+  0,
+  0,
+  '[DELETED]',
+  NULL,
+  CURRENT_TIMESTAMP
+);
+COMMIT;

참고: host_user_id 및 기타 필수 컬럼에 대한 적절한 값을 설정해야 합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
DELETE
FROM room
WHERE id = '00000000-0000-0000-0000-000000000000';
COMMIT;
INSERT INTO room (id, host_user_id, current_user_cnt, max_user_cnt, room_name, room_password, created_at)
VALUES (
'00000000-0000-0000-0000-000000000000',
'00000000-0000-0000-0000-000000000000',
0,
0,
'[DELETED]',
NULL,
CURRENT_TIMESTAMP
);
COMMIT;
🤖 Prompt for AI Agents
In src/main/resources/db/migration/V8__insert_room.sql lines 1-4, the migration
currently DELETEs the UUID used as DELETED_ROOM_ID, which contradicts the commit
message and breaks game_result references; replace the DELETE with an INSERT
that creates a dummy room row using that exact UUID and populate all NOT
NULL/required columns (host_user_id, name/title, created_at/updated_at,
status/visibility and any FKable fields) so existing game_result.room_id
references remain valid, then COMMIT; alternatively, if the dummy room already
exists in earlier migrations, remove this migration file entirely to avoid
redundant operations.