개발일지/TIL(Today I Learned)
2025-02-21 <최종 프로젝트 D-21>
프린스 알리
2025. 2. 21. 18:54
파티장 위임 기능
파티장이 탈퇴를 한 경우 다른 멤버에게 파티장 권한이 위임됩니다.
// leavePartyHandler 함수의 일부분
// 떠난 멤버가 파티장이면 파티장 교체
const partyLeader = party.getPartyLeader();
if (member[1] === partyLeader) {
// party클래스에서 파티장 교체
const memberIds = party.getAllMemberIds();
if (memberIds.length > 0) {
const newLeaderId = memberIds[0];
const newLeaderSocket = party.getSocketById(newLeaderId);
if (newLeaderSocket === -1) {
return console.log('새 파티장을 선출하는 과정에서 오류가 발생하였습니다.');
}
const newLeader = party.getMember(newLeaderSocket);
party.setPartyLeader(newLeader);
const members = party.getAllMemberEntries();
members.forEach(([key, value]) => {
const packet = Packet.S2CLeaveParty(
party.getId(),
party.getPartyLeaderId(),
party.getMemberCount(),
party.getAllMemberCardInfo(value.id),
);
key.write(packet);
});
const msgToParty = Packet.S2CChat(
0,
`${member[1].nickname}님이 파티를 떠나셨습니다.`,
);
party.notify(msgToParty);
// 떠난 멤버에게 메시지 전송
const msgToKickedMember = Packet.S2CDisbandParty('파티를 떠났습니다.');
member[0].write(msgToKickedMember);
}
}
예외 처리
(1) 스스로를 초대할 수 없습니다.
(2) 이미 초대를 받은 플레이어는 초대할 수 없습니다.
(3) 이미 파티에 소속된 플레이어는 초대할 수 없습니다.
클라이언트 코드
void OnSubmitClicked()
{
TMP_InputField inviteNickname = invitePartyPopUp.transform.Find("InviteNickname").GetComponent<TMP_InputField>();
string nickname = inviteNickname.text;
string myNickname = Party.instance.GetMyPlayerNickname();
// 내 닉네임이 아니고, 이미 참여 중인 파티원이 아닐 때
if (myNickname != nickname && Party.instance.GetMemberByNickname(nickname) == null)
{
SendInvitePartyPacket(nickname);
}
else
{
TownManager.Instance.UiChat.PushMessage("System", "초대를 보낼 수 없는 대상입니다.", true);
}
}
서버 코드
// invitePartyHandler 함수의 일부분
// 해당 플레이어가 파티 중이면 return
if (newMember.isInParty) {
const packet = Packet.S2CChat(0, '이미 파티에 소속된 플레이어입니다.');
return socket.write(packet);
}
// 상대방이 이미 초대를 받은 상태여도 return
if (newMember.isInvited) {
const packet = Packet.S2CChat(0, '지금은 초대장을 보낼 수 없습니다.');
return socket.write(packet);
}
참가 가능한 파티 목록 조회
서버 로직
파티 세션에서 인원이 1이상 5미만인 파티 20개를 검색하여 패킷으로 데이터를 전송합니다.
// partySession에서 인원이 1 이상 5미만인 파티를 20개 검색
const partySession = getPartySessions();
const parties = partySession.getAllPartyEntries();
let partyInfos = [];
for (const party of parties) {
const memberCount = party[1].getMemberCount();
if (memberCount >= 1 && memberCount < 5) {
const partyInfo = party[1].getPartyInfo();
if (!party[1].getPartyInfo) {
return socket.emit(
'error',
new CustomError(
ErrorCodes.PARTY_NOT_FOUND,
'파티 조회 중 오류가 발생했습니다.',
),
);
}
partyInfos.push(partyInfo);
if (partyInfos.length >= 20) break;
}
}
클라이언트 로직
전달받은 데이터를 기반으로 UI를 그려줍니다.
public void createPartyCard(S2CCheckPartyList pkt)
{
if (partyCardPrefab == null || partyListContainer == null)
{
Debug.LogError("PartyCard 프리팹 또는 Parent가 설정되지 않았습니다!");
return;
}
foreach (var partyInfo in pkt.PartyInfos)
{
string partyId = partyInfo.PartyId;
int leaderId = partyInfo.LeaderId;
int memberCount = partyInfo.MemberCount;
string nickname = GetPlayerByPlayerId(leaderId).nickname;
// 새로운 파티 카드 생성
GameObject newPartyCard = Instantiate(partyCardPrefab, partyListContainer);
// PartyCard 내의 UI 요소 가져오기
TMP_Text partyName = newPartyCard.transform.Find("PartyName").GetComponent<TMP_Text>();
TMP_Text memberCountText = newPartyCard.transform.Find("PartyName/MemberCount").GetComponent<TMP_Text>();
Button joinButton = newPartyCard.transform.Find("JoinBtn").GetComponent<Button>();
if (partyName != null) partyName.text = $"{nickname}님의 파티";
if (memberCountText != null) memberCountText.text = $"{memberCount}/5";
joinButton.onClick.RemoveAllListeners();
joinButton.onClick.AddListener(() => SendJoinPartyPacket(partyId, pkt.MemberId));
}
}