Project_xxx

[Projcet_] TDO - Trouble Shooting

wakelight23 2025. 1. 31. 21:38

Tower Defense Online - 게임 세션 관리 문제

● GameOver, 클라이언트 종료로 인한 게임 세션에 대한 문제가 발샘

 

● 게임을 1회 끝내고 재시작하면 gameSession에 대한 처리가 되지 않아 메모리에 쌓이고
   메모리 사용량이 높아지는 현상이 발견

● socket.on('end')를 받고 나서 게임이 종료된 gameSessions을 처리하지 않아 발생한 문제

 

어떻게 해결했는가

● gameSession을 삭제하는 메소드를 정의

// game.session.js
export const removeGameSession = (id) => {
  const index = gameSessions.findIndex((session) => session.id === id);
  if (index !== -1) {
    return gameSessions.splice(index, 1)[0];
  }
};

 - gameSession에 대한 메소드들은 game.Session.js에 정의하고 있다

 - 현재 접속한 User가 gameSessions에 있는지 확인 후 찾아서 삭제

 

● socket이 참가하고 있는 gameSessionId를 찾는 메소드 정의

// game.session.js
export const getGameSessionBySocket = (socket) => {
  return gameSessions.find((game) => game.users.some((user) => user.socket === socket));
};

 

● socket.on('end')를 받았을 때의 처리 (클라이언트 종료 시)

// 게임 세션에서 해당 소켓이 속한 게임 찾기
  const gameSession = getGameSessionBySocket(socket);
  if (gameSession) {
    // 게임 세션에서 유저 제거
    gameSession.removeUserUserId(removedUser.id);
    console.log(`${removedUser.id} 가 게임 세션 ${gameSession.id} 에서 삭제되었습니다.`);

    // 남아 있는 유저 처리
    if (gameSession.users.length === 1) {
      const winner = gameSession.users[0];

      // 승리 메시지 전송
      const gameOverNotificationpayload = {
        isWin: true,
      };
      const packetType = PacketType.GAME_OVER_NOTIFICATION;
      const gameDisconnected = createResponse(packetType, gameOverNotificationpayload);
      // 비정상 게임 종료시 winner에게 승리 메시지 전송 = 승리 판정
      winner.socket.write(gameDisconnected);
   	  // 게임 상태를 종료로 변경
      gameSession.state = 'ended';
    }

 - gameSessions에서 socket 기반으로 해당 게임 세션을 찾은 후 User 제거

 - 남아 있는 유저(클라이언트를 실행하는)에게는 승리 판정을 부여하여 게임이 종료되도록 유도

 - 클라이언트에 결과를 Response 해주고 gameSession의 상태를 'ended'로 정의하여 끝난 것을 표시

 

그 다음은?

● gameSession 내에 있는 User를 삭제해주었으니 이제는 gameSession 자체를 삭제해야한다.

// 게임 세션이 비어 있으면 삭제
    if (gameSession.users.length === 0 || gameSession.state === 'ended') {
      console.log(
        `
        [Game Session : ${gameSession.id}]
         세션에 User가 존재하지 않습니다.
         세션을 삭제합니다...
         `,
      );
      removeGameSession(gameSession.id);
    }

 - removeGameSession을 game.session.js에 메소드로 정의하여
   gameSessions에 유저가 없음 = length가 곧 0이라는 뜻이며 'ended' 문자열을 받았을 때 게임 세션 삭제


● 추가적으로 User에 대한 데이터도 한 번 더 초기화함으로서 게임을 재시작할 수 있도록 설정

    // 사용자 정보 초기화
    removedUser.clearUserData();

  - clearUserData()는 초기에 설정한 수치로 설정하는 초기화 메소드

 

 

해결!

처음 기획했던 클라이언트를 종료했을 때에는 gameSessions에서 User 데이터만 삭제하고
   gameSessions는 남아있도록 설계했지만 gameSessions가 계속해서 남아있으면 메모리 사용량에
   영향이 있을 것이기에 삭제되도록 기획 변경

 

● 도중에 상대방이 어떠한 이유로 클라이언트가 종료되어도 승리판정이 되도록 기획했기에

   게임이 지속적으로 진행이 가능해졌다.