[Projcet_] TDO - Trouble Shooting
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가 계속해서 남아있으면 메모리 사용량에
영향이 있을 것이기에 삭제되도록 기획 변경
● 도중에 상대방이 어떠한 이유로 클라이언트가 종료되어도 승리판정이 되도록 기획했기에
게임이 지속적으로 진행이 가능해졌다.