rabbit97 님의 블로그
20일 일지 본문
# 오늘의 회의 내용
노티피케이션을 어떻게 사용할 것인가?
결국 처음에 내가 구현했던 크리에이트 리스폰스 함수를 불러와서 보내는 방식으로 결정!
import { getGameSessionBySocket } from '../../sessions/game.session.js';
import { createResponse } from '../../utils/packet/response/createResponse.js';
import { PACKET_TYPE } from '../../constants/header.js';
const packetType = PACKET_TYPE;
// 유저 위치 업데이트 함수
const updateCharacterPosition = (gameSession, userId, x, y) => {
const targetUser = gameSession.users.find((user) => user.id === userId);
if (!targetUser) return false;
targetUser.position = { x, y };
return true;
};
// 위치 업데이트 요청 핸들러
const handlePositionUpdate = async (socket, payload) => {
try {
const { x, y } = payload;
const gameSession = getGameSessionBySocket(socket);
if (!gameSession) {
throw new Error('해당 유저의 게임 세션이 존재하지 않습니다.');
}
const currentUser = gameSession.users.find((user) => user.socket === socket);
if (!currentUser) {
throw new Error('유저가 존재하지 않습니다.');
}
const opponent = gameSession.users.find((user) => user.socket !== socket);
if (!opponent) {
throw new Error('상대 유저가 존재하지 않습니다.');
}
// 위치 업데이트 호출
const success = updateCharacterPosition(gameSession, currentUser.id, x, y);
if (success) {
const positionResponseData = {
success: true,
failCode: 0,
};
// 현재 유저에게 응답 전송
const positionResponse = await createResponse(
packetType.POSITION_UPDATE_RESPONSE,
socket.sequence,
positionResponseData,
);
socket.write(positionResponse);
// 상대 유저에게 알림 전송
const notificationData = {
userId: currentUser.id,
x,
y,
};
const notificationResponse = await createResponse(
packetType.POSITION_UPDATE_NOTIFICATION,
opponent.socket.sequence,
notificationData,
);
opponent.socket.write(notificationResponse);
} else {
throw new Error('캐릭터 위치 업데이트에 실패하였습니다.');
}
} catch (error) {
console.error('위치 업데이트 중 에러 발생:', error.message);
const errorResponse = createResponse(packetType.POSITION_UPDATE_RESPONSE, null, {
success: false,
message: 'Error updating position',
failCode: 1,
});
socket.write(errorResponse);
}
};
export default handlePositionUpdate;
그게에 맞춰 로직을 다시 변경하였다.
내일쯤이면 아마 게임 시작이 구현 될 것 같은데 이제 내 로직들을 합치면 된다
추가로 구현한 핸들러
디버프 관련 핸들러도 다시 수정하고
import { getGameSessionBySocket } from '../../sessions/game.session.js';
import { createResponse } from '../../utils/packet/response/createResponse.js';
import { PACKET_TYPE, WARNING_TYPE } from '../../constants/header.js';
const packetType = PACKET_TYPE;
// 디버프 전달 요청 핸들러
const handlePassDebuffRequest = async (socket, payload) => {
try {
const { targetUserId, debuffCardType } = payload;
const gameSession = getGameSessionBySocket(socket);
if (!gameSession) {
throw new Error('해당 유저의 게임 세션이 존재하지 않습니다.');
}
const currentUser = gameSession.users.find((user) => user.socket === socket);
if (!currentUser) {
throw new Error('현재 유저가 존재하지 않습니다.');
}
const targetUser = gameSession.users.find((user) => user.id === targetUserId);
if (!targetUser) {
throw new Error('타겟 유저가 존재하지 않습니다.');
}
// 디버프 카드를 전달 로직 추가 (현재 유저의 핸드에서 제거 후 타겟 유저에게 추가)
const debuffCardIndex = currentUser.character.handCards.findIndex(
(card) => card.type === debuffCardType,
);
if (debuffCardIndex === -1) {
throw new Error('유저의 핸드에 해당 디버프 카드가 존재하지 않습니다.');
}
const [debuffCard] = currentUser.character.handCards.splice(debuffCardIndex, 1);
targetUser.character.debuffs.push(debuffCard.type);
// 요청을 보낸 소켓에 성공 여부 보내기
const passDebuffResponse = createResponse(packetType.PASS_DEBUFF_RESPONSE, socket.sequence, {
success: true,
failCode: 0,
});
socket.write(passDebuffResponse);
// 노티피케이션 생성 및 전송
const notificationData = {
warningType: WARNING_TYPE,
expectedAt: Date.now(),
};
const notificationResponse = createResponse(
packetType.WARNING_NOTIFICATION,
targetUser.socket.sequence,
notificationData,
);
targetUser.socket.write(notificationResponse);
} catch (error) {
console.error('디버프 전달 중 에러 발생:', error.message);
// 요청을 보낸 소켓에 실패 여부 보내기
const errorResponse = createResponse(packetType.PASS_DEBUFF_RESPONSE, socket.sequence, {
success: false,
failCode: 1,
message: error.message || 'Debuff pass failed',
});
socket.write(errorResponse);
}
};
export default handlePassDebuffRequest;
유저 업데이트 로직도 수정을 했다
import { getGameSessionBySocket } from '../../sessions/game.session.js';
import { createResponse } from '../../utils/packet/response/createResponse.js';
import { PACKET_TYPE } from '../../constants/header.js';
const packetType = PACKET_TYPE;
// 유저 업데이트 알림 전송 함수
const sendUserUpdateNotification = (gameSession, payload) => {
const userUpdatePayload = {
// 업데이트 된 유저의 정보를 담음
users: payload.users.map((user) => ({
id: user.id,
nickname: user.nickname,
character: {
characterType: user.character.characterType,
roleType: user.character.roleType,
hp: user.character.hp,
weapon: user.character.weapon,
stateInfo: user.character.stateInfo,
equips: user.character.equips,
debuffs: user.character.debuffs,
handCards: user.character.handCards,
bbangCount: user.character.bbangCount,
handCardsCount: user.character.handCardsCount,
},
})),
};
gameSession.users.forEach((user) => {
const userUpdateNotification = createResponse(
packetType.USER_UPDATE_NOTIFICATION,
user.socket.sequence,
userUpdatePayload,
);
user.socket.write(userUpdateNotification);
});
};
// 유저 업데이트 요청 핸들러
const handleUserUpdate = async (socket, payload) => {
try {
const { users } = payload;
const gameSession = getGameSessionBySocket(socket);
if (!gameSession) {
throw new Error('해당 유저의 게임 세션이 존재하지 않습니다.');
}
// 모든 유저에게 유저 업데이트 알림 전송
sendUserUpdateNotification(gameSession, { users });
} catch (error) {
console.error('유저 업데이트 중 에러 발생:', error.message);
}
};
export default handleUserUpdate;
카드를 버리는 로직은 어제까지만 해도 알고리즘 풀듯이 했는데 사실 그럴 필요가 없는게
클라이언트 코드를 보니 대충 구현이 되어있고 서버에서는 잘 버렸는지 확인만 하면 되는거같아서
import { getGameSessionBySocket } from '../../sessions/game.session.js';
import { createResponse } from '../../utils/packet/response/createResponse.js';
import { PACKET_TYPE } from '../../constants/header.js';
const packetType = PACKET_TYPE;
// 카드 버리기 요청 핸들러
const handleDestroyCardRequest = async (socket, payload) => {
try {
const { destroyCards } = payload;
const gameSession = getGameSessionBySocket(socket);
if (!gameSession) {
throw new Error('해당 유저의 게임 세션이 존재하지 않습니다.');
}
const currentUser = gameSession.users.find((user) => user.socket === socket);
if (!currentUser) {
throw new Error('현재 유저가 존재하지 않습니다.');
}
// 버릴 카드 목록에서 카드들을 제거
destroyCards.forEach((destroyCard) => {
for (let i = 0; i < destroyCard.count; i++) {
const cardIndex = currentUser.character.handCards.findIndex(
(card) => card.type === destroyCard.type,
);
if (cardIndex !== -1) {
currentUser.character.handCards.splice(cardIndex, 1);
} else {
throw new Error(
`유저의 핸드에 ${destroyCard.type} 타입의 카드가 충분히 존재하지 않습니다.`,
);
}
}
});
// 현재 유저의 남은 카드 목록을 응답
const remainingHandCards = currentUser.character.handCards.map((card) => ({
type: card.type,
count: card.count,
}));
const destroyCardResponse = createResponse(packetType.DESTROY_CARD_RESPONSE, socket.sequence, {
handCards: remainingHandCards,
});
socket.write(destroyCardResponse);
} catch (error) {
console.error('카드 버리기 중 에러 발생:', error.message);
// 요청을 보낸 소켓에 실패 여부 보내기
const errorResponse = createResponse(packetType.DESTROY_CARD_RESPONSE, socket.sequence, {
handCards: currentUser.character.handCards.map((card) => ({
type: card.type,
count: card.count,
})),
});
socket.write(errorResponse);
}
};
export default handleDestroyCardRequest;
로직을 간단하게 수정하였고
플리마켓 관련 로직은 아직 작성 중이다.
import { getGameSessionBySocket } from '../../sessions/game.session.js';
import { createResponse } from '../../utils/packet/response/createResponse.js';
import { GLOBAL_FAIL_CODE, PACKET_TYPE } from '../../constants/header.js';
const packetType = PACKET_TYPE;
// 플리마켓 핸들러
const handleFleaMarketPick = async (socket, payload) => {
try {
const { pickIndex } = payload;
const gameSession = getGameSessionBySocket(socket);
if (!gameSession) {
throw new Error('해당 유저의 게임 세션이 존재하지 않습니다.');
}
const currentUser = gameSession.users.find((user) => user.socket === socket);
if (!currentUser) {
throw new Error('유저가 존재하지 않습니다.');
}
// 유효한 픽 인덱스인지 검증
const isValidPickIndex = (index) => {
// 플리마켓에서 유효한 인덱스인지 확인하는 로직을 구현
// 일단 다른거부터
// 플리마켓 카드 사용시 패킷 전송
return true;
};
if (!isValidPickIndex(pickIndex)) {
throw new Error('유효하지 않은 픽 인덱스입니다.');
}
const success = true;
if (success) {
const pickResponseData = {
success: true,
failCode: GlobalFailCode.NONE_FAILCODE,
};
// 현재 유저에게 응답 전송
const pickResponse = await createResponse(
packetType.FLEA_MARKET_PICK_RESPONSE,
socket.sequence,
pickResponseData,
);
socket.write(pickResponse);
} else {
throw new Error('플리마켓 픽 처리에 실패하였습니다.');
}
} catch (error) {
console.error('플리마켓 픽 중 에러 발생:', error.message);
const errorResponse = await createResponse(packetType.FLEA_MARKET_PICK_RESPONSE, null, {
success: false,
message: 'Error processing flea market pick',
failCode: GLOBAL_FAIL_CODE.UNKNOWN_ERROR,
});
socket.write(errorResponse);
}
};
export default handleFleaMarketPick;
이렇게 오늘 진행사항은 여기까지고
내일 내가 구현한 핸들러들이 잘 작동 했으면 좋겠다