1er commit
This commit is contained in:
37
src/protocol/PacketDispatcher.cpp
Normal file
37
src/protocol/PacketDispatcher.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "protocol/PacketDispatcher.h"
|
||||
|
||||
namespace td {
|
||||
namespace protocol {
|
||||
|
||||
void PacketDispatcher::RegisterHandler(PacketType type, PacketHandler* handler){
|
||||
auto found = std::find(m_Handlers[type].begin(), m_Handlers[type].end(), handler);
|
||||
if (found == m_Handlers[type].end())
|
||||
m_Handlers[type].push_back(handler);
|
||||
}
|
||||
|
||||
void PacketDispatcher::UnregisterHandler(PacketType type, PacketHandler* handler){
|
||||
auto found = std::find(m_Handlers[type].begin(), m_Handlers[type].end(), handler);
|
||||
if (found != m_Handlers[type].end())
|
||||
m_Handlers[type].erase(found);
|
||||
}
|
||||
|
||||
void PacketDispatcher::UnregisterHandler(PacketHandler* handler){
|
||||
for (auto& pair : m_Handlers){
|
||||
if (pair.second.empty()) continue;
|
||||
|
||||
PacketType type = pair.first;
|
||||
|
||||
m_Handlers[type].erase(std::remove(m_Handlers[type].begin(), m_Handlers[type].end(), handler), m_Handlers[type].end());
|
||||
}
|
||||
}
|
||||
|
||||
void PacketDispatcher::Dispatch(Packet* packet){
|
||||
if (!packet) return;
|
||||
|
||||
PacketType type = packet->getType();
|
||||
for (PacketHandler* handler : m_Handlers[type])
|
||||
packet->Dispatch(handler);
|
||||
}
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace td
|
||||
39
src/protocol/PacketFactory.cpp
Normal file
39
src/protocol/PacketFactory.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "protocol/PacketFactory.h"
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
namespace td {
|
||||
namespace protocol {
|
||||
namespace PacketFactory{
|
||||
|
||||
using PacketCreator = std::function<Packet*()>;
|
||||
|
||||
static std::map<PacketType, PacketCreator> packets = {
|
||||
{PacketType::PlayerLogin, []() -> Packet* {return new PlayerLoginPacket();} },
|
||||
{PacketType::WorldBeginData, []() -> Packet* {return new WorldBeginDataPacket();} },
|
||||
{PacketType::WorldData, []() -> Packet* {return new WorldDataPacket();} },
|
||||
{PacketType::KeepAlive, []() -> Packet* {return new KeepAlivePacket();} },
|
||||
{PacketType::UpdateMoney, []() -> Packet* {return new UpdateMoneyPacket();} },
|
||||
{PacketType::UpdateEXP, []() -> Packet* {return new UpdateExpPacket();} },
|
||||
{PacketType::UpdateLobbyTime, []() -> Packet* {return new UpdateLobbyTimePacket(); } },
|
||||
{PacketType::UpdateGameState, []() -> Packet* {return new UpdateGameStatePacket(); } },
|
||||
{PacketType::PlayerList, []() -> Packet* {return new PlayerListPacket(); } },
|
||||
{PacketType::PlayerJoin, []() -> Packet* {return new PlayerJoinPacket(); } },
|
||||
{PacketType::PlayerLeave, []() -> Packet* {return new PlayerLeavePacket(); } },
|
||||
{PacketType::ConnectionInfo, []() -> Packet* {return new ConnexionInfoPacket(); } },
|
||||
{PacketType::SelectTeam, []() -> Packet* {return new SelectTeamPacket(); } },
|
||||
{PacketType::UpdatePlayerTeam, []() -> Packet* {return new UpdatePlayerTeamPacket(); } },
|
||||
{PacketType::Disconnect, []() -> Packet* {return new DisconnectPacket(); } },
|
||||
{PacketType::ServerTps, []() -> Packet* {return new ServerTpsPacket(); } },
|
||||
{PacketType::SpawnMob, []() -> Packet* {return new SpawnMobPacket(); } },
|
||||
};
|
||||
|
||||
Packet* createPacket(PacketType type, DataBuffer& buffer){
|
||||
Packet* packet = packets[type]();
|
||||
packet->Deserialize(buffer);
|
||||
return packet;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace protocol
|
||||
} // namespace td
|
||||
409
src/protocol/Protocol.cpp
Normal file
409
src/protocol/Protocol.cpp
Normal file
@@ -0,0 +1,409 @@
|
||||
#include "protocol/PacketHandler.h"
|
||||
#include <cmath>
|
||||
|
||||
#define REGISTER_DISPATCH_CLASS(className) void className::Dispatch(PacketHandler* handler){handler->HandlePacket(this);}
|
||||
|
||||
namespace td {
|
||||
namespace protocol {
|
||||
|
||||
const int BITS_IN_BYTE = 8;
|
||||
const int BITS_IN_LONG = BITS_IN_BYTE * sizeof(std::uint64_t);
|
||||
|
||||
unsigned int countBits(unsigned int number){
|
||||
// log function in base 2
|
||||
// take only integer part
|
||||
return (int)std::log2(number) + 1;
|
||||
}
|
||||
|
||||
DataBuffer& operator<<(DataBuffer& buffer, game::TilePtr tile){
|
||||
buffer << tile->getType();
|
||||
switch (tile->getType()){
|
||||
case game::TileType::Tower:{
|
||||
const std::shared_ptr<game::TowerTile>& towerTile = (const std::shared_ptr<game::TowerTile>&) tile;
|
||||
buffer << towerTile->color_palette_ref << towerTile->team_owner;
|
||||
break;
|
||||
}
|
||||
case game::TileType::Walk:{
|
||||
const std::shared_ptr<game::WalkableTile>& walkTile = (const std::shared_ptr<game::WalkableTile>&) tile;
|
||||
buffer << walkTile->direction;
|
||||
break;
|
||||
}
|
||||
case game::TileType::Decoration:{
|
||||
const std::shared_ptr<game::DecorationTile>& decoTile = (const std::shared_ptr<game::DecorationTile>&) tile;
|
||||
buffer << decoTile->color_palette_ref;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
DataBuffer& operator>>(DataBuffer& buffer, game::TilePtr& tile){
|
||||
game::TileType tileType;
|
||||
buffer >> tileType;
|
||||
switch (tileType){
|
||||
case game::TileType::Tower:{
|
||||
std::shared_ptr<game::TowerTile> tilePtr = std::make_shared<game::TowerTile>();
|
||||
buffer >> tilePtr->color_palette_ref >> tilePtr->team_owner;
|
||||
tile = tilePtr;
|
||||
break;
|
||||
}
|
||||
case game::TileType::Walk:{
|
||||
std::shared_ptr<game::WalkableTile> tilePtr = std::make_shared<game::WalkableTile>();
|
||||
buffer >> tilePtr->direction;
|
||||
tile = tilePtr;
|
||||
break;
|
||||
}
|
||||
case game::TileType::Decoration:{
|
||||
std::shared_ptr<game::DecorationTile> tilePtr = std::make_shared<game::DecorationTile>();
|
||||
buffer >> tilePtr->color_palette_ref;
|
||||
tile = tilePtr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
DataBuffer PlayerLoginPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_PlayerName;
|
||||
return data;
|
||||
}
|
||||
|
||||
void PlayerLoginPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_PlayerName;
|
||||
}
|
||||
|
||||
DataBuffer WorldBeginDataPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
const game::TowerTileColorPalette towerTilePalette = m_World->getTowerTileColorPalette();
|
||||
const std::vector<game::Color>& decoTilePalette = m_World->getDecorationPalette();
|
||||
|
||||
data << getID() << towerTilePalette << m_World->getWalkableTileColor()
|
||||
<< (std::uint16_t)decoTilePalette.size();
|
||||
|
||||
// deco color palette
|
||||
std::size_t bufferSize = data.GetSize();
|
||||
data.Resize(bufferSize + decoTilePalette.size() * sizeof(game::Color));
|
||||
|
||||
memcpy((void*)data.data() + bufferSize, decoTilePalette.data(), decoTilePalette.size() * sizeof(game::Color));
|
||||
|
||||
const game::Spawn& redSpawn = m_World->getRedSpawn(), blueSpawn = m_World->getBlueSpawn();
|
||||
const game::TeamCastle& redCastle = m_World->getRedCastle(), blueCastle = m_World->getBlueCastle();
|
||||
|
||||
data << redSpawn << redCastle;
|
||||
data << blueSpawn << blueCastle;
|
||||
|
||||
// tile palette
|
||||
data << m_World->getTilePalette().size();
|
||||
|
||||
for (game::TilePtr tile : m_World->getTilePalette()){
|
||||
data << tile;
|
||||
}
|
||||
|
||||
data << m_World->getSpawnColors();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void WorldBeginDataPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_TowerPlacePalette >> m_WalkablePalette;
|
||||
|
||||
std::uint16_t decoPaletteSize;
|
||||
data >> decoPaletteSize;
|
||||
|
||||
std::size_t decoPalletteSizeByte = decoPaletteSize * sizeof(game::Color);
|
||||
|
||||
m_DecorationPalette.reserve(decoPaletteSize);
|
||||
|
||||
memcpy((void*)m_DecorationPalette.data(), data.data() + data.GetReadOffset(), decoPalletteSizeByte);
|
||||
|
||||
data.SetReadOffset(data.GetReadOffset() + decoPalletteSizeByte);
|
||||
|
||||
data >> m_RedSpawn >> m_RedTower;
|
||||
data >> m_BlueSpawn >> m_BlueTower;
|
||||
|
||||
std::size_t tilePaletteSize;
|
||||
data >> tilePaletteSize;
|
||||
|
||||
m_TilePalette.reserve(tilePaletteSize);
|
||||
|
||||
for (int i = 0; i < tilePaletteSize; i++){
|
||||
game::TilePtr tile;
|
||||
data >> tile;
|
||||
m_TilePalette.push_back(tile);
|
||||
}
|
||||
|
||||
data >> m_SpawnColorPalette;
|
||||
}
|
||||
|
||||
typedef std::vector<uint64_t> ChunkPackedData;
|
||||
|
||||
DataBuffer WorldDataPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_World->getChunks().size();
|
||||
for (const auto& pair : m_World->getChunks()){
|
||||
game::ChunkCoord coords = pair.first;
|
||||
game::ChunkPtr chunk = pair.second;
|
||||
|
||||
data << coords.first << coords.second << chunk->palette.size();
|
||||
|
||||
std::size_t bufferSize = data.GetSize();
|
||||
data.Resize(data.GetSize() + chunk->palette.size() * sizeof(game::ChunkPalette::value_type));
|
||||
memcpy((void*)data.data() + bufferSize, chunk->palette.data(), chunk->palette.size() * sizeof(game::ChunkPalette::value_type));
|
||||
|
||||
std::uint8_t bitsPerTile = countBits(chunk->palette.size());
|
||||
|
||||
game::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1);
|
||||
|
||||
ChunkPackedData chunkData(game::Chunk::ChunkSize / (BITS_IN_BYTE * sizeof(ChunkPackedData::value_type) / bitsPerTile), 0);
|
||||
|
||||
for (int tileNumber = 0; tileNumber < game::Chunk::ChunkSize; tileNumber++){
|
||||
int startLong = (tileNumber * bitsPerTile) / BITS_IN_LONG;
|
||||
int startOffset = (tileNumber * bitsPerTile) % BITS_IN_LONG;
|
||||
int endLong = ((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG;
|
||||
|
||||
std::uint64_t value = chunk->tiles[tileNumber];
|
||||
|
||||
value &= individualValueMask;
|
||||
|
||||
|
||||
chunkData[startLong] |= (value << startOffset);
|
||||
|
||||
if (startLong != endLong){
|
||||
chunkData[endLong] = (value >> (BITS_IN_LONG - startOffset));
|
||||
}
|
||||
}
|
||||
|
||||
bufferSize = data.GetSize();
|
||||
data.Resize(data.GetSize() + chunkData.size() * sizeof(ChunkPackedData::value_type));
|
||||
memcpy((void*)data.data() + bufferSize, chunkData.data(), chunkData.size() * sizeof(ChunkPackedData::value_type));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void WorldDataPacket::Deserialize(DataBuffer& data){
|
||||
std::size_t chunkCount;
|
||||
data >> chunkCount;
|
||||
|
||||
for (int chunkNumber = 0; chunkNumber < chunkCount; chunkNumber++){
|
||||
game::ChunkPtr chunk = std::make_shared<game::Chunk>();
|
||||
|
||||
game::ChunkCoord::first_type chunkX, chunkY;
|
||||
data >> chunkX >> chunkY;
|
||||
|
||||
std::size_t chunkPaletteSize;
|
||||
data >> chunkPaletteSize;
|
||||
|
||||
game::ChunkPalette chunkPalette(chunkPaletteSize);
|
||||
|
||||
memcpy((void*)chunkPalette.data(), data.data() + data.GetReadOffset(), chunkPaletteSize * sizeof(game::ChunkPalette::value_type));
|
||||
data.SetReadOffset(data.GetReadOffset() + chunkPaletteSize * sizeof(game::ChunkPalette::value_type));
|
||||
|
||||
chunk->palette = chunkPalette;
|
||||
|
||||
std::uint8_t bitsPerTile = countBits(chunkPaletteSize);
|
||||
|
||||
// A bitmask that contains bitsPerTile set bits
|
||||
game::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1);
|
||||
|
||||
ChunkPackedData chunkData(game::Chunk::ChunkSize / (BITS_IN_BYTE * sizeof(ChunkPackedData::value_type) / bitsPerTile), 0);
|
||||
|
||||
memcpy((void*)chunkData.data(), data.data() + data.GetReadOffset(), chunkData.size() * sizeof(ChunkPackedData::value_type));
|
||||
data.SetReadOffset(data.GetReadOffset() + chunkData.size() * sizeof(ChunkPackedData::value_type));
|
||||
|
||||
for (int tileNumber = 0; tileNumber < game::Chunk::ChunkSize; tileNumber++){
|
||||
int startLong = (tileNumber * bitsPerTile) / BITS_IN_LONG;
|
||||
int startOffset = (tileNumber * bitsPerTile) % BITS_IN_LONG;
|
||||
int endLong = ((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG;
|
||||
|
||||
game::ChunkData::value_type value;
|
||||
if (startLong == endLong){
|
||||
value = (chunkData[startLong] >> startOffset);
|
||||
}
|
||||
else{
|
||||
int endOffset = BITS_IN_LONG - startOffset;
|
||||
value = (chunkData[startLong] >> startOffset | chunkData[endLong] << endOffset);
|
||||
}
|
||||
value &= individualValueMask;
|
||||
|
||||
chunk->tiles[tileNumber] = value;
|
||||
}
|
||||
|
||||
|
||||
m_Chunks.insert({{chunkX, chunkY}, chunk});
|
||||
}
|
||||
}
|
||||
|
||||
DataBuffer KeepAlivePacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_AliveID;
|
||||
return data;
|
||||
}
|
||||
|
||||
void KeepAlivePacket::Deserialize(DataBuffer& data){
|
||||
data >> m_AliveID;
|
||||
}
|
||||
|
||||
DataBuffer UpdateMoneyPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_NewAmount;
|
||||
return data;
|
||||
}
|
||||
|
||||
void UpdateMoneyPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_NewAmount;
|
||||
}
|
||||
|
||||
DataBuffer UpdateExpPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_NewAmount;
|
||||
return data;
|
||||
}
|
||||
|
||||
void UpdateExpPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_NewAmount;
|
||||
}
|
||||
|
||||
DataBuffer UpdateLobbyTimePacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_RemainingTime;
|
||||
return data;
|
||||
}
|
||||
|
||||
void UpdateLobbyTimePacket::Deserialize(DataBuffer& data){
|
||||
data >> m_RemainingTime;
|
||||
}
|
||||
|
||||
DataBuffer UpdateGameStatePacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_GameState;
|
||||
return data;
|
||||
}
|
||||
|
||||
void UpdateGameStatePacket::Deserialize(DataBuffer& data){
|
||||
data >> m_GameState;
|
||||
}
|
||||
|
||||
DataBuffer PlayerListPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << (std::uint8_t)m_Players.size();
|
||||
for (auto pair : m_Players){
|
||||
data << pair.first << pair.second.name << pair.second.team;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void PlayerListPacket::Deserialize(DataBuffer& data){
|
||||
std::uint8_t playerCount;
|
||||
data >> playerCount;
|
||||
|
||||
for (int i = 0; i < playerCount; i++){
|
||||
std::uint8_t playerID;
|
||||
PlayerInfo playerInfo;
|
||||
data >> playerID >> playerInfo.name >> playerInfo.team;
|
||||
m_Players.insert({playerID, playerInfo});
|
||||
}
|
||||
}
|
||||
|
||||
DataBuffer PlayerJoinPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_PlayerID << m_PlayerName;
|
||||
return data;
|
||||
}
|
||||
|
||||
void PlayerJoinPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_PlayerID >> m_PlayerName;
|
||||
}
|
||||
|
||||
DataBuffer PlayerLeavePacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_PlayerID;
|
||||
return data;
|
||||
}
|
||||
|
||||
void PlayerLeavePacket::Deserialize(DataBuffer& data){
|
||||
data >> m_PlayerID;
|
||||
}
|
||||
|
||||
DataBuffer ConnexionInfoPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_ConnectionID;
|
||||
return data;
|
||||
}
|
||||
|
||||
void ConnexionInfoPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_ConnectionID;
|
||||
}
|
||||
|
||||
DataBuffer SelectTeamPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_SelectedTeam;
|
||||
return data;
|
||||
}
|
||||
|
||||
void SelectTeamPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_SelectedTeam;
|
||||
}
|
||||
|
||||
DataBuffer UpdatePlayerTeamPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_PlayerID << m_SelectedTeam;
|
||||
return data;
|
||||
}
|
||||
|
||||
void UpdatePlayerTeamPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_PlayerID >> m_SelectedTeam;
|
||||
}
|
||||
|
||||
DataBuffer DisconnectPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_Reason;
|
||||
return data;
|
||||
}
|
||||
|
||||
void DisconnectPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_Reason;
|
||||
}
|
||||
|
||||
DataBuffer ServerTpsPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_TPS << m_PacketSendTime;
|
||||
return data;
|
||||
}
|
||||
|
||||
void ServerTpsPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_TPS >> m_PacketSendTime;
|
||||
}
|
||||
|
||||
DataBuffer SpawnMobPacket::Serialize() const{
|
||||
DataBuffer data;
|
||||
data << getID() << m_MobID << m_MobType << m_MobLevel << m_MobDirection
|
||||
<< m_Sender << m_MobX << m_MobY;
|
||||
return data;
|
||||
}
|
||||
|
||||
void SpawnMobPacket::Deserialize(DataBuffer& data){
|
||||
data >> m_MobID >> m_MobType >> m_MobLevel >> m_MobDirection
|
||||
>> m_Sender >> m_MobX >> m_MobY;
|
||||
}
|
||||
|
||||
REGISTER_DISPATCH_CLASS(PlayerLoginPacket);
|
||||
REGISTER_DISPATCH_CLASS(WorldBeginDataPacket);
|
||||
REGISTER_DISPATCH_CLASS(WorldDataPacket);
|
||||
REGISTER_DISPATCH_CLASS(KeepAlivePacket);
|
||||
REGISTER_DISPATCH_CLASS(UpdateExpPacket);
|
||||
REGISTER_DISPATCH_CLASS(UpdateMoneyPacket);
|
||||
REGISTER_DISPATCH_CLASS(UpdateLobbyTimePacket);
|
||||
REGISTER_DISPATCH_CLASS(UpdateGameStatePacket);
|
||||
REGISTER_DISPATCH_CLASS(PlayerListPacket);
|
||||
REGISTER_DISPATCH_CLASS(PlayerJoinPacket);
|
||||
REGISTER_DISPATCH_CLASS(PlayerLeavePacket);
|
||||
REGISTER_DISPATCH_CLASS(ConnexionInfoPacket);
|
||||
REGISTER_DISPATCH_CLASS(SelectTeamPacket);
|
||||
REGISTER_DISPATCH_CLASS(UpdatePlayerTeamPacket);
|
||||
REGISTER_DISPATCH_CLASS(DisconnectPacket);
|
||||
REGISTER_DISPATCH_CLASS(ServerTpsPacket);
|
||||
REGISTER_DISPATCH_CLASS(SpawnMobPacket);
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace td
|
||||
Reference in New Issue
Block a user