#include "protocol/PacketHandler.h" #include #define REGISTER_DISPATCH_CLASS(className) void className::Dispatch(PacketHandler* handler) const {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 game::TowerTile* towerTile = (const game::TowerTile*)tile.get(); buffer << towerTile->color_palette_ref << towerTile->team_owner; break; } case game::TileType::Walk: { const game::WalkableTile* walkTile = (const game::WalkableTile*)tile.get(); buffer << walkTile->direction; break; } case game::TileType::Decoration: { const game::DecorationTile* decoTile = (const game::DecorationTile*)tile.get(); buffer << decoTile->color_palette_ref; break; } default: break; } return buffer; } DataBuffer& operator>>(DataBuffer& buffer, game::TilePtr& tile) { game::TileType tileType; buffer >> tileType; switch (tileType) { case game::TileType::Tower: { std::shared_ptr tilePtr = std::make_shared(); buffer >> tilePtr->color_palette_ref >> tilePtr->team_owner; tile = tilePtr; break; } case game::TileType::Walk: { std::shared_ptr tilePtr = std::make_shared(); buffer >> tilePtr->direction; tile = tilePtr; break; } case game::TileType::Decoration: { std::shared_ptr tilePtr = std::make_shared(); buffer >> tilePtr->color_palette_ref; tile = tilePtr; break; } default: 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::SerializeCustom() const { DataBuffer data; const game::TowerTileColorPalette towerTilePalette = m_Header.m_TowerPlacePalette; const std::vector& decoTilePalette = m_Header.m_DecorationPalette; data << getID() << towerTilePalette << m_Header.m_WalkablePalette << (std::uint16_t)decoTilePalette.size(); // deco color palette std::size_t bufferSize = data.GetSize(); data.Resize(bufferSize + decoTilePalette.size() * sizeof(game::Color)); memcpy((std::uint8_t*)data.data() + bufferSize, decoTilePalette.data(), decoTilePalette.size() * sizeof(game::Color)); data << m_Header.m_Background; const game::Spawn& redSpawn = m_Header.m_RedSpawn, blueSpawn = m_Header.m_BlueSpawn; const game::TeamCastle& redCastle = m_Header.m_RedCastle, blueCastle = m_Header.m_BlueCastle; data << redSpawn << static_cast(redCastle); data << blueSpawn << static_cast(blueCastle); // tile palette data << static_cast(m_Header.m_TilePalette.size()); for (game::TilePtr tile : m_Header.m_TilePalette) { data << tile; } data << m_Header.m_SpawnColorPalette; return data; } DataBuffer WorldBeginDataPacket::Serialize() const { DataBuffer data; const game::TowerTileColorPalette towerTilePalette = m_Header.m_World->getTowerTileColorPalette(); const std::vector& decoTilePalette = m_Header.m_World->getDecorationPalette(); data << getID() << towerTilePalette << m_Header.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((std::uint8_t*)data.data() + bufferSize, decoTilePalette.data(), decoTilePalette.size() * sizeof(game::Color)); data << m_Header.m_World->getBackgroundColor(); const game::Spawn& redSpawn = m_Header.m_World->getRedTeam().getSpawn(), blueSpawn = m_Header.m_World->getBlueTeam().getSpawn(); const game::TeamCastle& redCastle = m_Header.m_World->getRedTeam().getCastle(), blueCastle = m_Header.m_World->getBlueTeam().getCastle(); data << redSpawn << static_cast(redCastle); data << blueSpawn << static_cast(blueCastle); // tile palette data << static_cast(m_Header.m_World->getTilePalette().size()); for (game::TilePtr tile : m_Header.m_World->getTilePalette()) { data << tile; } data << m_Header.m_World->getSpawnColors(); return data; } void WorldBeginDataPacket::Deserialize(DataBuffer& data) { data >> m_Header.m_TowerPlacePalette >> m_Header.m_WalkablePalette; std::uint16_t decoPaletteSize; data >> decoPaletteSize; std::size_t decoPalletteSizeByte = decoPaletteSize * sizeof(game::Color); m_Header.m_DecorationPalette.resize(decoPaletteSize); memcpy((std::uint8_t*)m_Header.m_DecorationPalette.data(), data.data() + data.GetReadOffset(), decoPalletteSizeByte); data.SetReadOffset(data.GetReadOffset() + decoPalletteSizeByte); data >> m_Header.m_Background; utils::shape::Rectangle redCastle, blueCastle; data >> m_Header.m_RedSpawn >> redCastle; data >> m_Header.m_BlueSpawn >> blueCastle; m_Header.m_RedCastle.setShape(redCastle); m_Header.m_BlueCastle.setShape(blueCastle); std::uint64_t tilePaletteSize; data >> tilePaletteSize; m_Header.m_TilePalette.reserve(tilePaletteSize); for (std::uint64_t tileNumber = 0; tileNumber < tilePaletteSize; tileNumber++) { game::TilePtr tile; data >> tile; m_Header.m_TilePalette.push_back(tile); } data >> m_Header.m_SpawnColorPalette; } typedef std::vector ChunkPackedData; DataBuffer WorldDataPacket::SerializeCustom() const { DataBuffer data; data << getID() << m_WorldData.m_Chunks.size(); for (const auto& pair : m_WorldData.m_Chunks) { game::ChunkCoord coords = pair.first; game::ChunkPtr chunk = pair.second; data << coords.x << coords.y << (std::uint64_t)chunk->palette.size(); std::size_t bufferSize = data.GetSize(); data.Resize(data.GetSize() + chunk->palette.size() * sizeof(game::ChunkPalette::value_type)); memcpy((std::uint8_t*)data.data() + bufferSize, chunk->palette.data(), chunk->palette.size() * sizeof(game::ChunkPalette::value_type)); std::uint8_t bitsPerTile = countBits(chunk->palette.size()); game::Chunk::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((std::uint8_t*)data.data() + bufferSize, chunkData.data(), chunkData.size() * sizeof(ChunkPackedData::value_type)); } return data; } 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.x << coords.y << (std::uint64_t)chunk->palette.size(); std::size_t bufferSize = data.GetSize(); data.Resize(data.GetSize() + chunk->palette.size() * sizeof(game::ChunkPalette::value_type)); memcpy((std::uint8_t*)data.data() + bufferSize, chunk->palette.data(), chunk->palette.size() * sizeof(game::ChunkPalette::value_type)); std::uint8_t bitsPerTile = countBits(chunk->palette.size()); game::Chunk::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((std::uint8_t*)data.data() + bufferSize, chunkData.data(), chunkData.size() * sizeof(ChunkPackedData::value_type)); } return data; } void WorldDataPacket::Deserialize(DataBuffer& data) { std::uint64_t chunkCount; data >> chunkCount; for (std::uint64_t chunkNumber = 0; chunkNumber < chunkCount; chunkNumber++) { game::ChunkPtr chunk = std::make_shared(); decltype(game::ChunkCoord::x) chunkX, chunkY; data >> chunkX >> chunkY; std::uint64_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::Chunk::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::Chunk::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_WorldData.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; } DataBuffer PlaceTowerPacket::Serialize() const { DataBuffer data; data << getID() << m_TowerX << m_TowerY << m_TowerType; return data; } void PlaceTowerPacket::Deserialize(DataBuffer& data) { data >> m_TowerX >> m_TowerY >> m_TowerType; } DataBuffer WorldAddTowerPacket::Serialize() const { DataBuffer data; data << getID() << m_TowerID << m_TowerX << m_TowerY << m_TowerType << m_Builder; return data; } void WorldAddTowerPacket::Deserialize(DataBuffer& data) { data >> m_TowerID >> m_TowerX >> m_TowerY >> m_TowerType >> m_Builder; } DataBuffer RemoveTowerPacket::Serialize() const { DataBuffer data; data << getID() << m_TowerID; return data; } void RemoveTowerPacket::Deserialize(DataBuffer& data) { data >> m_TowerID; } DataBuffer SendMobsPacket::Serialize() const { DataBuffer data; data << getID() << static_cast(m_MobSends.size()); for (const MobSend& mobSend : m_MobSends) { data << mobSend; } return data; } void SendMobsPacket::Deserialize(DataBuffer& data) { std::uint8_t mobSendCount; data >> mobSendCount; protocol::MobSend mobSend; for (int i = 0; i < mobSendCount; i++) { data >> mobSend; m_MobSends.push_back(mobSend); } } DataBuffer UpgradeTowerPacket::Serialize() const { DataBuffer data; data << getID() << m_TowerID << m_TowerLevel; return data; } void UpgradeTowerPacket::Deserialize(DataBuffer& data) { data >> m_TowerID >> m_TowerLevel; } DataBuffer UpdateCastleLifePacket::Serialize() const { DataBuffer data; data << getID() << m_CastleLife << m_Team; return data; } void UpdateCastleLifePacket::Deserialize(DataBuffer& data) { data >> m_CastleLife >> m_Team; } DataBuffer UpdateMobStatesPacket::Serialize() const { DataBuffer data; data << getID() << static_cast(m_MobStates.size()); for (auto mobState : m_MobStates) { data << mobState; } return data; } void UpdateMobStatesPacket::Deserialize(DataBuffer& data) { std::uint64_t mobCount; data >> mobCount; m_MobStates.resize(mobCount); for (std::uint64_t mobIndex = 0; mobIndex < mobCount; mobIndex++) { data >> m_MobStates[mobIndex]; } } 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); REGISTER_DISPATCH_CLASS(PlaceTowerPacket); REGISTER_DISPATCH_CLASS(WorldAddTowerPacket); REGISTER_DISPATCH_CLASS(RemoveTowerPacket); REGISTER_DISPATCH_CLASS(SendMobsPacket); REGISTER_DISPATCH_CLASS(UpgradeTowerPacket); REGISTER_DISPATCH_CLASS(UpdateCastleLifePacket); REGISTER_DISPATCH_CLASS(UpdateMobStatesPacket); } // namespace protocol } // namespace td