개발일지/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));
    }
}