이전 시간에 만든 Packet을 쓰거나 읽을 때 필요한 공통적인 부분을 모듈화 해보자
ServerPacketHandler.h, ServerPacketHandler.cpp
#pragma once
enum
{
S_TEST = 1
};
struct BuffData
{
uint64 buffId;
float remainTime;
};
class ServerPacketHandler
{
public:
static void HandlePacket(BYTE* buffer, int32 len);
static SendBufferRef Make_S_TEST(uint64 id, uint32 hp, uint16 attack, vector<BuffData> buffs);
};
#include "pch.h"
#include "ServerPacketHandler.h"
#include "BufferReader.h"
#include "BufferWriter.h"
void ServerPacketHandler::HandlePacket(BYTE* buffer, int32 len)
{
BufferReader br(buffer, len);
PacketHeader header;
br.Peek(&header);
switch (header.id)
{
default:
break;
}
}
SendBufferRef ServerPacketHandler::Make_S_TEST(uint64 id, uint32 hp, uint16 attack, vector<BuffData> buffs)
{
SendBufferRef sendBuffer = GSendBufferManager->Open(4096);
BufferWriter bw(sendBuffer->Buffer(), sendBuffer->AllocSize());
PacketHeader* header = bw.Reserve<PacketHeader>();
// id(uint64), 체력(uint32), 공격력(uint16)
bw << id << hp << attack;
// 가변 데이터
bw << (uint16)buffs.size();
for (BuffData& buff : buffs)
{
bw << buff.buffId << buff.remainTime;
}
header->size = bw.WriteSize();
header->id = S_TEST; // 1 : Test Msg
sendBuffer->Close(bw.WriteSize());
return sendBuffer;
}
ClientPacketHandler.h, ClientPacketHandler.cpp
#pragma once
enum
{
S_TEST = 1
};
class ClientPacketHandler
{
public:
static void HandlePacket(BYTE* buffer, int32 len);
static void Handle_S_TEST(BYTE* buffer, int32 len);
};
#include "pch.h"
#include "ClientPacketHandler.h"
#include "BufferReader.h"
void ClientPacketHandler::HandlePacket(BYTE* buffer, int32 len)
{
BufferReader br(buffer, len);
PacketHeader header;
br >> header;
switch (header.id)
{
case S_TEST:
Handle_S_TEST(buffer, len);
break;
}
}
// 패킷 설계 TEMP
struct BuffData
{
uint64 buffId;
float remainTime;
};
struct S_TEST
{
uint64 id;
uint32 hp;
uint16 attack;
// 가변 데이터
// 1) 문자열 (ex. name)
// 2) 그냥 바이트 배열 (ex. 길드 이미지)
// 3) 일반 리스트
vector<int64> buffs;
};
void ClientPacketHandler::Handle_S_TEST(BYTE* buffer, int32 len)
{
BufferReader br(buffer, len);
PacketHeader header;
br >> header;
uint64 id;
uint32 hp;
uint16 attack;
br >> id >> hp >> attack;
cout << "ID: " << id << " HP : " << hp << " ATT : " << attack << endl;
vector<BuffData> buffs;
uint16 buffCount;
br >> buffCount;
buffs.resize(buffCount);
for (int32 i = 0; i < buffCount; i++)
{
br >> buffs[i].buffId >> buffs[i].remainTime;
}
cout << "BuffCount : " << buffCount << endl;
for (int32 i = 0; i < buffCount; i++)
{
cout << "BufInfo : " << buffs[i].buffId << " " << buffs[i].remainTime << endl;
}
}
GameSession.cpp
void GameSession::OnRecvPacket(BYTE* buffer, int32 len)
{
ServerPacketHandler::HandlePacket(buffer, len);
}
GameServer.cpp
...
while (true)
{
vector<BuffData> buffs{ BuffData{100, 1.5f}, BuffData{200, 2.3f}, BuffData{300, 0.7f} };
SendBufferRef sendBuffer = ServerPacketHandler::Make_S_TEST(1001, 100, 10, buffs);
GSessionManager.Broadcast(sendBuffer);
this_thread::sleep_for(250ms);
}
...
DummyClient.cpp
...
virtual void OnRecvPacket(BYTE* buffer, int32 len) override
{
ClientPacketHandler::HandlePacket(buffer, len);
}
...
BufferWriter.h
class BufferWriter
{
...
// 삭제 start
template<typename T>
BufferWriter& operator<<(const T& src);
// 삭제 end
}
...
// 삭제 start
template<typename T>
BufferWriter& BufferWriter::operator<<(const T& src)
{
*reinterpret_cast<T*>(&_buffer[_pos]) = src;
_pos += sizeof(T);
return *this;
}
// 삭제 end
template<typename T>
BufferWriter& BufferWriter::operator<<(T&& src)
{
using DataType = std::remove_reference_t<T>;
*reinterpret_cast<DataType*>(&_buffer[_pos]) = std::forward<DataType>(src);
_pos += sizeof(T);
return *this;
}
1. 기존 방법 안좋은 점
- Write 한 순서대로 Read 해야 함.
- Packet 지금 1 종류임.
2. 보편참조가 일어나는 조건은?
- rvalue 파라메터로 받는 template 함수, 같은 파라메터 이지만 lvalue로 받는 template 함수 있을 때, 전자 template 함수만 쓰이게 됨.
- 보편참조 함수에 lvalue 들어오면 "const T&" 로 rvalue 이면 "T&&"로 들어온다.
3. BufferWriter operator<<에 컴파일 에러가 생기는 이유와 해결방?
- 보편참조 함수에 uint64 들어옴 > 함수 안에서 const uint64& (= T값)의 포인터를 추출하려고 시도하기 때문임.
- 레퍼런스를 뺀 나머지만 이용하여 연산하면 해결됨.
- std::remove_reference_t<T> 는 T에 레퍼런스가 있으면 떼줌.
참조 : [C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버 대시보드 - 인프런 | 강의 (inflearn.com)
Unicode (0) | 2023.05.07 |
---|---|
Buffer Helpers (0) | 2023.04.19 |
Packet Session (0) | 2023.04.16 |
SendBuffer Pooling (0) | 2023.04.05 |
SendBuffer (0) | 2021.12.21 |
댓글 영역