글을 쓰기에 앞서 4주동안 열심히 스파르타 코딩 클럽에서 최종프로젝트를 하던 나의 조가 해체가 되었다.
그렇게 튜터님들과 팀원들의 노력으로 다른 조에 병합하게 되었고, 그곳의 서버에 무언가 데이터를 싸버린 것을 본 저는 핸들러가 제대로 동작할 수 있게 노력을 하였습니다.
1. 프로토 메세지를 확인
message SkillInfo {
int32 skillId = 1; // 스킬 ID
float damageRate = 2; // 스킬 계수
float coolTime = 3; // 스킬 쿨타임
}
message C_GetSkill {
int32 skillId = 1; // 장착된 스킬 ID
int32 itemInstanceId = 2; // 고유 아이템 ID
int32 slotIndex = 3; // 슬롯 인덱스
}
message S_GetSkill {
SkillInfo skillInfo = 1; // 스킬 슬롯 정보
int32 playerId = 2;
int32 itemInstanceId = 3; // 고유 아이템 ID
}
2. 핸들러 흐름 설계
이 핸들러는 특정 유저가 스킬을 주웠을 때
클라에서 보내준 payload를 구조 분해 할당으로 데이터를 받아온다.
특정 유저를 구분짓는 방법이 socket.id가 playerId로 구분지어 놨으니 해당 user를 찾는다.
스킬은 던전에서만 얻을 수도, 사용할 수도 있다.
맵핑된 스킬 정보를 가져오고
해당 유저가 있는 던전을 찾고 그 던전에서 해당 유저의 정보를 가져온다.
던전 유저 정보의 스킬 리스트에 추가해준다.
여기에서 플레이어는 스킬을 최대 2개만 소지할 수 있다.
필요한 정보를 클라에 보내준다.
3. 흐름 설계 대로 핸들러 작성
이 핸들러는 특정 유저가 스킬을 주웠을 때
클라에서 보내준 payload를 구조 분해 할당으로 데이터를 받아온다.
특정 유저를 구분짓는 방법이 socket.id가 playerId로 구분지어 놨으니 해당 user를 찾는다.
const getSkillHandler = ({ socket, payload }) => {
const { skillId, itemInstanceId, slotIndex } = payload;
const playerId = socket.id;
try {
const user = getUserById(playerId); // 유저 세션에서 해당 유저 찾기
if (!user) {
logger.error(`getSkillHandler. Could not found user : ${playerId}`);
return;
}
} catch (error) {
handleError(socket, error);
}
};
export default getSkillHandler;
스킬은 던전에서만 얻을 수도, 사용할 수도 있다.
맵핑된 스킬 정보를 가져오고
해당 유저가 있는 던전을 찾고 그 던전에서 해당 유저의 정보를 가져온다.
const getSkillHandler = ({ socket, payload }) => {
const { skillId, itemInstanceId, slotIndex } = payload;
const playerId = socket.id;
try {
const user = getUserById(playerId);
if (!user) {
logger.error(`getSkillHandler. Could not found user : ${playerId}`);
return;
}
if (!user.dungeonId) {
logger.error(`getSkillHandler. this player not in the dungeon : ${playerId}`);
return;
}
const skillAssets = getGameAssets().skillInfo; // 맵핑된 스킬 정보 가져오기
const skillData = skillAssets[skillId]; // ID로 직접 접근
if (!skillData) {
logger.error(`스킬 정보를 찾을 수 없습니다. skillId: ${skillId}`);
return;
}
const dungeon = getDungeonSession(user.dungeonId);
const dungeonUser = dungeon.users.get(playerId);
if (!dungeonUser) {
logger.error(`getSkillHandler. could not found dungeonUser`);
return;
}
} catch (error) {
handleError(socket, error);
}
};
export default getSkillHandler;
던전 유저 정보의 스킬 리스트에 추가해준다.
여기에서 플레이어는 스킬을 최대 2개만 소지할 수 있다.
필요한 정보를 클라에 보내준다.
const droppedSkillInfo = dungeon.getDroppedObject(playerId, skillId, itemInstanceId);
if (!droppedSkillInfo) {
return;
}
//지정 슬롯외의 값이 오면 폐기하겠단 의미이므로 삭제
if (slotIndex > 2 || slotIndex < 0) {
logger.info(`getSkillHandler. no available skill slot : ${slotIndex}`);
return;
}
dungeonUser.skillList[skillId] = { slot: slotIndex, ...skillData, lastUseTime: 0 };
const skillPayload = {
skillInfo: { ...skillData, skillId },
playerId,
itemInstanceId,
};
const buffer = createResponse(PACKET_ID.S_GetSkill, skillPayload);
enqueueSend(socket.UUID, buffer);
logger.info(`getSkillHandler 성공: playerId=${playerId}, skillId=${skillId}`);
4. 항상 클라와 테스트 하기전 해야하는 것들
- 클라가 완성이 되어 있고 클라랑 테스트가 가능 하다면 바로 클라와 테스트해도 됩니다.
- 클라가 미완성이면 해당 핸들러의 데이터 송 수신이 잘 되는지 테스트 클라를 데이터를 하드 코딩해서 테스트 후
- 다음 업무로 넘어간다.
5. 느낀점
스파르타 코딩 클럽에서 늘 하던 핸들러 작성이었기 때문에 어려운 부분은 없었습니다.
하지만, 처음 여기 조로 합병 되고나서 망가져 있는 코드 흐름을 다시 정리해놓고 동작도 안되는 코드들을 Merge까지 해놓은 상황을 보고 몹시 힘들었지만 덕분에 즐거운 핸들러 작성이 되었습니다.
내부에 클래스는 어떻게 쓰는지 해당 던전 세션, 유저 세션은 어떻게 관리하고 있는지에 대해서는 일부러 적지 않았습니다.
핸들러 작성법에 대해서 적고 싶었기 때문입니다.
'TIL' 카테고리의 다른 글
Node.js 서버 user, dungeon 관리 작성 - 최종프로젝트 2 (0) | 2024.12.17 |
---|---|
자원 전쟁 (서버) 프로젝트 - 용광로 만들기 2탄 (0) | 2024.12.05 |
자원 전쟁 (서버) 프로젝트 - 용광로 만들기 1탄 (0) | 2024.12.05 |
C# .csv파일 변환 방법과 예시 (0) | 2024.11.26 |
Class와 Structure의 차이점 및 사용 목적 (0) | 2024.11.26 |