하아찡
[C++서버] 서버 채널 분할 본문
언리얼 버전 5.5.3
서버언어 C++로 구성했습니다.
카테고리명이 이것저것 테스트입니다. 서버공부를 하는데있어서 만들어보고 싶었던 기능을 만들어보는중입니다.
이사람은 이렇게 만들어봤구나 참고해주세요~
일단 구성을 생각해봤을때 맵(Level)과 채널이 필요할듯 합니다.
맵은 고유값으로 가지고있고 해당 맵값으로 접근하면 해당 채널값을 넘겨주는 방향으로 진행했습니다.
패킷은 Protobuf를 사용해서 구성은 아래와 같이했습니다.
enum LevelType
{
LEVEL_TYPE_NONE = 0;
LEVEL_TYPE_BASE = 1;
LEVEL_TYPE_TEST = 2;
}
기본적인 맵 값 입니다. 해당 값을 가지고 각각 맵이 가지고있는 채널값을 넘겨줄 예정입니다.
그리고 유저가 해당 맵값과 채널값을 가지게 합니다.
message ObjectInfo
{
uint64 object_id = 1;
PosInfo posinfo = 2;
ObjectType object_type = 3;
LevelType leveltype = 4;
uint64 chanel = 5;
}
해당 맵값과 채널값을 가지고 바로바로 데이터를 꺼내다 쓰기위해 위와같이 구조를 정했습니다.
클래스는 기존에 사용하던 Room클래스와 MapManager 그리고 RoomManager를 추가했습니다.
기존에 Room이 개별인 채널의 기능을 하고
RoomManager는 Room을 가지고 있고 해당 Room에 일정 인원수가 찰경우 새로운 채널을 추가하여 만들어주는 작업을 해줍니다.
마지막으로 MapManager는 RoomManager를 연결시켜줄 예정입니다.
맵이 추가될때마다 해당 클래스 생성자에다가 맵을 추가해줘야 합니다. 여기서 생성한 RoomManager는 프로그램 종료시까지 계속 들고 있을예정입니다.
MapManager.h
#include "JobQueue.h"
class MapManager : public JobQueue
{
public:
MapManager();
virtual ~MapManager();
public:
bool JoinMap(Protocol::LevelType levelType, ObjectRef object);
public:
void SetMaxPeople(int32 maxPeople);
RoomRef GetRoom(ObjectRef object);
RoomManagerRef GetRoomManager(ObjectRef object);
private:
void CreateMap(Protocol::LevelType levelType);
private:
int32 MaxPeople = 30; // 한채널 최대 접속가능인원
unordered_map<uint64, RoomManagerRef> Maps;
};
extern MapManagerRef GMapManager;
MapManager.cpp
#include "pch.h"
#include "RoomManager.h"
#include "Player.h"
#include "MapManager.h"
MapManagerRef GMapManager = make_shared<MapManager>();
MapManager::MapManager()
{
CreateMap(Protocol::LEVEL_TYPE_BASE); // 베이스맵
CreateMap(Protocol::LEVEL_TYPE_TEST); // 테스트맵
}
MapManager::~MapManager()
{
}
bool MapManager::JoinMap(Protocol::LevelType levelType, ObjectRef object)
{
RoomManagerRef joinMap = Maps[levelType];
if (joinMap == nullptr) {
//등록된 맵이 없을경우 생성하고 접속 시킴.
CreateMap(levelType);
}
joinMap->JoinChanel(object);
return true;
}
void MapManager::SetMaxPeople(int32 maxPeople)
{
MaxPeople = maxPeople;
}
RoomRef MapManager::GetRoom(ObjectRef object)
{
if (auto player = dynamic_pointer_cast<Player>(object)) {
uint64 map = player->objectInfo->leveltype();
uint64 chanel = player->objectInfo->chanel();
return Maps[map]->Rooms[chanel];
}
else {
return nullptr;
}
}
RoomManagerRef MapManager::GetRoomManager(ObjectRef object)
{
if (auto player = dynamic_pointer_cast<Player>(object)) {
uint64 map = player->objectInfo->leveltype();
return Maps[map];
}
else {
return nullptr;
}
}
void MapManager::CreateMap(Protocol::LevelType levelType)
{
// 이미 생성된 맵정보면 생성하지않음.
// 한번 생성된 맵정보는 생성 후 제거가 되지않음.
// 내부 RoomManager에서 따로 처리하던가 함.
if(Maps[levelType] != nullptr) return;
RoomManagerRef map = make_shared<RoomManager>();
Maps[levelType] = map;
}
현재 코드에서는 최대인원수를 설정하지 못합니다.
생성자에선 맵정보를 생성합니다. 해당 맵정보를 생성해 줘야 RoomManager가 생성이 되며, 해당 Index로 접근해서 RoomManager를 사용해서 채널에 접속할 수 있습니다.
JoinMap함수는 혹시나 테스트 중에 맵 데이터를 생성자에서 빼먹었을때 추가해주기 위한 코드입니다.
그리고 나서 RoomManager에 있는 JoinChanel 함수를 호출해서 해당 맵 채널에 자동으로 접속하게 됩니다.
GetRoom과 GetRoomManager는 패킷 처리쪽에서 해당 값을 바로 불러다 쓰기위해 추가해두었는데 MapManager쪽에서 다처리하게 하고싶은데 일단 이렇게 처리해두었습니다.
해당 함수는 Map값과 Chanel값을 받아 각각의 RoomRef와 RoomManager값을 바로 가져와서 사용합니다.
RoomManager.h
#include "JobQueue.h"
class RoomManager : public JobQueue
{
public:
void JoinChanel(ObjectRef object);
void JoinChanel(uint32 chanel, ObjectRef object);
void LeaveChanel(PlayerRef player);
public:
//전체 메시지
void Broadcast(SendBufferRef sendBuffer);
public:
unordered_map<uint64, RoomRef> Rooms;
private:
uint64 GetFirstAvailableID();
RoomRef CreateChanel();
void RemoveRoom(uint64 RoomID);
private:
//테스트용으로 값을 낮게 설정
int MaxPlayer = 2;
};
RoomManager.cpp
#include "pch.h"
#include "RoomManager.h"
#include "Player.h"
#include "Room.h"
RoomRef RoomManager::CreateChanel()
{
RoomRef chanel = make_shared<Room>();
return chanel;
}
void RoomManager::RemoveRoom(uint64 RoomID)
{
if (Rooms.find(RoomID) == Rooms.end())
return;
// TODO
// 지우기전에 해당 채널에 사람이있는지 체크를 해야함.
RoomRef room = Rooms[RoomID];
Rooms.erase(RoomID);
return;
}
void RoomManager::JoinChanel(ObjectRef object)
{
for (auto& room : Rooms)
{
if (room.second->GetEnterPlayerCnt() >= MaxPlayer) continue;
JoinChanel(room.first, object);
return;
}
// 여기왔으면 방을못찾아서 알아서 새롭게 넣어주셈
JoinChanel(GetFirstAvailableID(), object);
}
void RoomManager::JoinChanel(uint32 chanel, ObjectRef object)
{
if (Rooms[chanel] == nullptr) {
// 해당 채널이 없을경우 채널을 생성함
Rooms[chanel] = CreateChanel();
cout << "Create Chanel : " << chanel << endl;
}
if (Rooms[chanel]->GetEnterPlayerCnt() >= MaxPlayer) {
// 접속채널 인원 초과 다른채널로 안내
uint64 firstChanel = GetFirstAvailableID();
Rooms[firstChanel] = CreateChanel();
chanel = firstChanel;
}
PlayerRef player = dynamic_pointer_cast<Player>(object);
Rooms[chanel]->EnterRoom(player);
if (player != nullptr) {
// 플레이어 일경우
player->SetMyChanel(chanel);
}
cout << "Join Chanel : " << chanel << " Player Chanel : " << player->GetMyChanel() << endl;
}
uint64 RoomManager::GetFirstAvailableID()
{
std::set<uint64> UsedIDs;
for (const auto& pair : Rooms)
{
UsedIDs.insert(pair.first);
}
int NewID = 0;
while (UsedIDs.find(NewID) != UsedIDs.end())
{
++NewID;
}
return NewID;
}
void RoomManager::LeaveChanel(PlayerRef player)
{
//PlayerRef player = dynamic_pointer_cast<Player>(object);
if(player == nullptr) return;
//현재 접속된 채널을 가져옴.
uint64 ObjectChanel = player->GetMyChanel();
if(Rooms[ObjectChanel] == nullptr) return;
Rooms[ObjectChanel]->LeaveRoom(player);
// 플레이어 수
uint64 enterCnt = Rooms[ObjectChanel]->GetEnterPlayerCnt();
if (enterCnt == 0) {
//방에 남은 사람이 없을경우 해당방은 사라짐.
cout << "Remove Chanel : " << ObjectChanel << endl;
Rooms.erase(ObjectChanel);
}
}
void RoomManager::Broadcast(SendBufferRef sendBuffer)
{
// 매니저에 등록된 룸접속자 모두에게 데이터를 뿌림.
for (auto& room : Rooms)
{
room.second->Broadcast(sendBuffer);
}
}
채널을 생성시켜주고 채널을 삭제 시켜주는 기능이 있습니다.
처음 접속할때는 채널을 자동으로 남은곳에 배치해주고 해당 맵에서 떠났을때 채널에 사람이 없는경우 채널을 제거해줍니다.
서버측 결과물
4명을 접속 시켰습니다. 채널이 없어서 채널을 생성시켜주고 한 채널에 최대 2명까지 접속이 가능하게 설정해두었으니 2명이 접속한뒤에 접속 할 수 있는 채널이 없기때문에 또다른 채널을 생성해서 했습니다.
각각의 채널에서 구분된 결과
1번 채널에 있는 유저를 다 나가면 자동으로 해당 채널에 사람이없는걸 확인 후 해당 채널을 지웁니다.
'C++ > 이것저것서버테스트' 카테고리의 다른 글
[언리얼5, C++] 맵 이동 - 2 (0) | 2025.02.25 |
---|---|
[언리얼5, C++] 맵 이동 (0) | 2025.02.23 |
[언리얼5] 채팅 (0) | 2025.02.20 |
[언리얼5] 서버 캐릭터 움직임 처리 - 2 (0) | 2025.02.18 |
[언리얼5] 서버 캐릭터 움직임 처리 (0) | 2025.02.16 |