KoreanFoodie's Study
[C++ 게임 서버] 5-6. 패킷 직렬화 #3 본문
[C++ 게임 서버] 5-6. 패킷 직렬화 #3
핵심 :
1. 가변 데이터 안에 가변 데이터를 넣는 경우도, 결국 Offset 과 Count 를 이용해 버퍼에 데이터를 기록하는 방식으로 처리한다.
2. 추후에 소개할 ProtoBuf 를 이용하면, 패킷을 만들 때 가변 데이터를 일일히 코드로 넣는 귀찮음을 줄일 수 있다(다만 불필요한 복사가 있을 수는 있음).
저번에는 가변 데이터를 패킷에 넣어 보았는데... 만약 가변 데이터 안에 또 가변 데이터가 있다면 어떻게 해야 할까?
예를 들어, BuffListItem 이라는 구조체에 해당 버프의 대상들 정보(Victims 라고 하자)를 담는다면 어떻게 해야 할까?
struct BuffsListItem
{
uint64 buffId;
float remainTime;
// Victim List
uint16 victimsOffset;
uint16 victimsCount;
};
일단 위의 데이터가 들어가야 하는 패킷은 아래처럼 정의할 수 있을 것이다.
// [ PKT_S_TEST ][BuffsListItem BuffsListItem BuffsListItem][victim victim][victim victim]
struct PKT_S_TEST
{
uint16 packetSize; // 공용 헤더
uint16 packetId; // 공용 헤더
uint64 id; // 8
uint32 hp; // 4
uint16 attack; // 2
uint16 buffsOffset;
uint16 buffsCount;
};
패킷의 정의는 거의 똑같은데, 잘 보면 기존에 BuffsListItem 으로 할당된 공간 외에, victim 에 대한 정보가 버퍼에 기록되어야 함을 알 수 있다.
사실 이전에 우리가 만들어 놓은 PacketList 를 활용하면, 쉽게 확장을 할 수 있다. 즉, ServerPacketHandler 에서는 아래와 같이 버퍼를 사용하게 될 것이다 :
// [ PKT_S_TEST ][BuffsListItem BuffsListItem BuffsListItem][victim victim]
class PKT_S_TEST_WRITE
{
public:
using BuffsListItem = PKT_S_TEST::BuffsListItem;
using BuffsList = PacketList<PKT_S_TEST::BuffsListItem>;
using BuffsVictimsList = PacketList<uint64>;
PKT_S_TEST_WRITE(uint64 id, uint32 hp, uint16 attack)
{
_sendBuffer = GSendBufferManager->Open(4096);
_bw = BufferWriter(_sendBuffer->Buffer(), _sendBuffer->AllocSize());
_pkt = _bw.Reserve<PKT_S_TEST>();
_pkt->packetSize = 0; // To Fill
_pkt->packetId = S_TEST;
_pkt->id = id;
_pkt->hp = hp;
_pkt->attack = attack;
_pkt->buffsOffset = 0; // To Fill
_pkt->buffsCount = 0; // To Fill
}
BuffsList ReserveBuffsList(uint16 buffCount)
{
BuffsListItem* firstBuffsListItem = _bw.Reserve<BuffsListItem>(buffCount);
_pkt->buffsOffset = (uint64)firstBuffsListItem - (uint64)_pkt;
_pkt->buffsCount = buffCount;
return BuffsList(firstBuffsListItem, buffCount);
}
BuffsVictimsList ReserveBuffsVictimsList(BuffsListItem* buffsItem, uint16 victimsCount)
{
uint64* firstVictimsListItem = _bw.Reserve<uint64>(victimsCount);
buffsItem->victimsOffset = (uint64)firstVictimsListItem - (uint64)_pkt;
buffsItem->victimsCount = victimsCount;
return BuffsVictimsList(firstVictimsListItem, victimsCount);
}
SendBufferRef CloseAndReturn()
{
// 패킷 사이즈 계산
_pkt->packetSize = _bw.WriteSize();
_sendBuffer->Close(_bw.WriteSize());
return _sendBuffer;
}
private:
PKT_S_TEST* _pkt = nullptr;
SendBufferRef _sendBuffer;
BufferWriter _bw;
};
코드가 조금 길어졌는데, 사실 이전과 달라진 부분은 크게 없다. 😅
ReserveBuffsVictimsList 를 보면, victimsCount 만큼의 공간을 확보한 다음, Offset 과 Count 를 넣어주고 있다. 이는 기존에 BuffList 에 대한 정보를 버퍼에 기록하는 것과 비슷한 작업이다!
그리고 이제는 리스트 안에 리스트가 있는 형태라, packetSize 가 한번에 계산이 안되었었다. 😂 이를 위해, 마지막에 CloseAndReturn 함수를 통해 패킷의 총 사이즈를 기록할 수 있도록 만들어줬다.
그렇다면 실제로 GameServer 에서는 데이터를 어떻게 넣어주어야 할까? 사실 이 부분이 조금 귀찮을 수 있는데, 왜냐하면 아래와 같이 일일히 데이터를 넣어 주어야 하기 때문이다.
// [ PKT_S_TEST ]
PKT_S_TEST_WRITE pktWriter(1001, 100, 10);
// [ PKT_S_TEST ][BuffsListItem BuffsListItem BuffsListItem]
PKT_S_TEST_WRITE::BuffsList buffList = pktWriter.ReserveBuffsList(3);
buffList[0] = { 100, 1.5f };
buffList[1] = { 200, 2.3f };
buffList[2] = { 300, 0.7f };
PKT_S_TEST_WRITE::BuffsVictimsList vic0 = pktWriter.ReserveBuffsVictimsList(&buffList[0], 3);
{
vic0[0] = 1000;
vic0[1] = 2000;
vic0[2] = 3000;
}
PKT_S_TEST_WRITE::BuffsVictimsList vic1 = pktWriter.ReserveBuffsVictimsList(&buffList[1], 1);
{
vic1[0] = 1000;
}
PKT_S_TEST_WRITE::BuffsVictimsList vic2 = pktWriter.ReserveBuffsVictimsList(&buffList[2], 2);
{
vic2[0] = 3000;
vic2[1] = 5000;
}
SendBufferRef sendBuffer = pktWriter.CloseAndReturn();
하지만 데이터 구조가 복잡해지고, 양이 많아지면 위와 같은 방식으로 작업하는 것은 애로 사항이 있을 것이다. 물론 이를 해결하기 위해, ProtoBuf 를 사용하기도 하는데... 그건 곧 다루게 될 것이다. 😉
그럼 ClientPacketHandler 에서는, 다음처럼 기존과 크게 다르지 않게 데이터를 읽을 수 있게 된다!
PKT_S_TEST::BuffsList buffs = pkt->GetBuffsList();
for (auto& buff : buffs)
{
PKT_S_TEST::BuffsVictimsList victims = pkt->GetBuffsVictimList(&buff);
for (auto& victim : victims)
cout << "Victim : " << victim << endl;
}
'Game Dev > Game Server' 카테고리의 다른 글
[C++ 게임 서버] 5-8. 패킷 자동화 #1 (0) | 2023.12.18 |
---|---|
[C++ 게임 서버] 5-7. Protobuf (0) | 2023.12.16 |
[C++ 게임 서버] 5-5. 패킷 직렬화 #2 (0) | 2023.12.16 |
[C++ 게임 서버] 5-4. 패킷 직렬화 #1 (0) | 2023.12.15 |
[C++ 게임 서버] 5-3. Unicode (0) | 2023.12.15 |