본문 바로가기
개인공부/IOCP 서버 제작 실습

IOCP 서버 제작 실습 8

by 하고싶은건많은놈 2023. 3. 27.

Room을 생성하여 채팅을 할 수 있도록 구현

 

  • Room 생성
    1. [PacketManager] CreateRommManager() 함수에서 RoomManager 객체 생성
    2. [RoomManager] Init() 함수에서 maxRoomCount 만큼의 Room 객체를 생성해두고 추후 사용
  • Room 입장
    1. [PacketManager] ProcessPacket() 함수에서 확인한 패킷 데이터의 Id가 ROOM_ENTER_REQUEST일 경우
    2. [PacketManger] ProcessEnterRoom() 함수에서 응답으로 보내줄 패킷을 생성
      • 유저가 존재하지 않는 경우 에러코드로 ENTER_ROOM_NOT_FIND_USER를 가진 응답을 전송
      • 로그인하지 않은 유저의 요청일 경우 에러코드로 ENTER_ROOM_INVALID_USER_STATUS를 가진 응답을 전송
      • 유저가 이미 방에 들어가 있는 경우 에러코드로 ENTER_ROOM_ALREADY를 가진 응답을 전송
      • 그 외에는 Room의 EnterUser() 함수를 호출하여 응답 패킷의 Result 값으로 저장하여 전송
    3. [RoomManager] EnterUser() 함수에서 roomNumber에 따른 Room을 선택
      • 올바르지 않은 roomNumber일 경우 에러코드로 ROOM_INVALID_INDEX를 반환
      • 정상적인 roomNumber일 경우 Room의 EnterUser() 함수를 호출하여 반환값으로 사용
    4. [Room] EnterUser() 함수에서 해당 방의 유저 카운트를 확인
      • 유저 카운트 수가 최대 유저 수 이상이라면 에러코드로 ENTER_ROOM_FULL_USER를 반환
      • 최대 유저 수를 넘지 않는다면 유저 리스트에 유저를 추가하고, 유저의 EnterRoom() 함수를 호출하여 유저에게도 Room에 들어갔음을 알림
  • Room 퇴장
    •  Room 입장 과정과 로직은 거의 동일
    • 에러 케이스 처리만 조금씩 다른 부분이 존재
  • Room 채팅
    1. [PacketManager] ProcessPacket() 함수에서 확인한 패킷 데이터의 Id가 ROOM_CHAT_REQUEST일 경우
    2. [PacketManger] ProcessRoomChatMessage() 함수에서 응답으로 보내줄 패킷을 생성, 각종 에러 케이스 처리 후 응답 패킷을 전송
    3. [Room] NotifyChat() 함수에서 ROOM_CHAT_REQUEST_PACKET을 생성
    4. [Room] SendToAllUser() 함수에서 Room에 존재하는 유저들에게 패킷을 전송

 


 

  • Room.h
    • Room에 속해있는 유저들을 list 형태로 관리 
std::list<User*>	mUserList;

void SendToAllUser(const UINT16 dataSize_, char* data_, const INT32 passUserIndex_, bool exceptMe)
{
    for (auto pUser : mUserList)
    {
        if (pUser == nullptr)
        {
            continue;
        }

        if (exceptMe && pUser->GetNetConnIdx() == passUserIndex_)
        {
            continue;
        }

        SendPacketFunc((UINT32)pUser->GetNetConnIdx(), (UINT32)dataSize_, data_);
    }
}

UINT16 EnterUser(User *user_)
{
    if (mCurrentUserCount >= mMaxUserCount)
    {
        return (UINT16)ERROR_CODE::ENTER_ROOM_FULL_USER;
    }

    mUserList.push_back(user_);
    ++mCurrentUserCount;

    user_->EnterRoom(mRoomNum);
    return (UINT16)ERROR_CODE::NONE;
}

UINT16 LeaveUser(User *leaveUser_)
{
    bool finduser = false;
    mUserList.remove_if([&finduser, leaveUserId = leaveUser_->GetUserId()](User*& pUser) {
        if (leaveUserId == pUser->GetUserId())
        {
            finduser = true;
        }
        return leaveUserId == pUser->GetUserId();
    });
    if (finduser == false)
    {
        return (UINT16)ERROR_CODE::ROOM_NOT_FIND_USER;
    }

    return (UINT16)ERROR_CODE::NONE;
}

void NotifyChat(INT32 clientIndex_, const char *userID_, const char *msg_)
{
    ROOM_CHAT_NOTIFY_PACKET roomChatNotifyPacket;
    roomChatNotifyPacket.PacketId = (UINT16)PACKET_ID::ROOM_CHAT_NOTIFY;
    roomChatNotifyPacket.PacketLength = sizeof(roomChatNotifyPacket);

    CopyMemory(roomChatNotifyPacket.Msg, msg_, sizeof(roomChatNotifyPacket.Msg));
    CopyMemory(roomChatNotifyPacket.UserID, userID_, sizeof(roomChatNotifyPacket.UserID));
    SendToAllUser(sizeof(roomChatNotifyPacket), (char*)&roomChatNotifyPacket, clientIndex_, false);
}
};

 

 

  • RoomManager.h
    • 생성되어있는 Room들을 vector 형태로 관리
std::vector<Room*>	mRoomList;

void Init(const UINT32 beginRoomNumber_, const UINT32 maxRoomCount_, const UINT32 maxRoomUserCount_)
{
    mBeginRoomNumber = beginRoomNumber_;
    mMaxRoomCount = maxRoomCount_;
    mEndRoomNumber = beginRoomNumber_ + maxRoomCount_;

    mRoomList = std::vector<Room*>(maxRoomCount_);

    for (UINT32 i = 0; i < maxRoomCount_; i++)
    {
        mRoomList[i] = new Room();
        mRoomList[i]->SendPacketFunc = SendPacketFunc;
        mRoomList[i]->Init((i + beginRoomNumber_), maxRoomUserCount_);
    }
}

UINT16 EnterUser(UINT32 roomNumber_, User* user_)
{
    auto pRoom = GetRoomByNumber(roomNumber_);
    if (pRoom == nullptr)
    {
        std::cout << "Invalid RoomNumber\n";
        return (UINT16)ERROR_CODE::ROOM_INVALID_INDEX;
    }

    return pRoom->EnterUser(user_);
}

UINT16 LeaveUser(INT32 roomNumber_, User *user_)
{
    auto pRoom = GetRoomByNumber(roomNumber_);
    if (pRoom == nullptr)
    {
        return (UINT16)ERROR_CODE::ROOM_INVALID_INDEX;
    }

    user_->SetDomainState(User::DOMAIN_STATE::LOGIN);
    return (pRoom->LeaveUser(user_));
}

'개인공부 > IOCP 서버 제작 실습' 카테고리의 다른 글

IOCP 서버 제작 실습 10  (1) 2023.03.27
IOCP 서버 제작 실습 9  (0) 2023.03.27
IOCP 서버 제작 실습 7  (0) 2023.03.25
IOCP 서버 제작 실습 6  (0) 2023.03.23
IOCP 서버 제작 실습 5  (0) 2023.03.23

댓글