diff --git a/include/protocol/Protocol.h b/include/protocol/Protocol.h index 122666c..901286f 100644 --- a/include/protocol/Protocol.h +++ b/include/protocol/Protocol.h @@ -33,6 +33,25 @@ enum class PacketType : std::uint8_t { WorldRemoveTower, }; +struct WorldHeader { + game::TowerTileColorPalette m_TowerPlacePalette; + game::Color m_WalkablePalette; + std::vector m_DecorationPalette; + + game::SpawnColorPalette m_SpawnColorPalette; + + game::TilePalette m_TilePalette; + + game::Spawn m_RedSpawn, m_BlueSpawn; + game::TeamCastle m_RedCastle, m_BlueCastle; + + const game::World* m_World; +}; + +struct WorldData { + std::unordered_map m_Chunks; +}; + class Packet { public: Packet() {} @@ -83,21 +102,12 @@ public: class WorldBeginDataPacket : public Packet { private: - game::TowerTileColorPalette m_TowerPlacePalette; - game::Color m_WalkablePalette; - std::vector m_DecorationPalette; - - game::SpawnColorPalette m_SpawnColorPalette; - - game::TilePalette m_TilePalette; - - game::Spawn m_RedSpawn, m_BlueSpawn; - game::TeamCastle m_RedTower, m_BlueTower; - - const game::World* m_World; + WorldHeader m_Header; public: WorldBeginDataPacket() {} - WorldBeginDataPacket(const game::World* world) : m_World(world) {} + WorldBeginDataPacket(const game::World* world) { + m_Header.m_World = world; + } virtual ~WorldBeginDataPacket() {} virtual DataBuffer Serialize() const; @@ -106,24 +116,27 @@ public: virtual PacketType getType() const { return PacketType::WorldBeginData; } - const game::TowerTileColorPalette& getTowerTilePalette() const { return m_TowerPlacePalette; } - const game::Color& getWalkableTileColor() const { return m_WalkablePalette; } - const std::vector& getDecorationPalette() const { return m_DecorationPalette; } + const game::TowerTileColorPalette& getTowerTilePalette() const { return m_Header.m_TowerPlacePalette; } + const game::Color& getWalkableTileColor() const { return m_Header.m_WalkablePalette; } + const std::vector& getDecorationPalette() const { return m_Header.m_DecorationPalette; } - const game::Spawn& getRedSpawn() const { return m_RedSpawn; } - const game::Spawn& getBlueSpawn() const { return m_BlueSpawn; } + const game::Spawn& getRedSpawn() const { return m_Header.m_RedSpawn; } + const game::Spawn& getBlueSpawn() const { return m_Header.m_BlueSpawn; } - const game::SpawnColorPalette& getSpawnPalette() const { return m_SpawnColorPalette; } + const game::SpawnColorPalette& getSpawnPalette() const { return m_Header.m_SpawnColorPalette; } - const game::TeamCastle& getRedCastle() const { return m_RedTower; } - const game::TeamCastle& getBlueCastle() const { return m_BlueTower; } + const game::TeamCastle& getRedCastle() const { return m_Header.m_RedCastle; } + const game::TeamCastle& getBlueCastle() const { return m_Header.m_BlueCastle; } - const game::TilePalette getTilePalette() const { return m_TilePalette; } + const game::TilePalette getTilePalette() const { return m_Header.m_TilePalette; } + + DataBuffer SerializeCustom() const; // allow serialisation with invalid World member + void setWorldHeader(const WorldHeader& header) { m_Header = header; } }; class WorldDataPacket : public Packet { private: - std::unordered_map m_Chunks; + WorldData m_WorldData; const game::World* m_World; public: @@ -137,7 +150,10 @@ public: virtual PacketType getType() const { return PacketType::WorldData; } - const std::unordered_map& getChunks() const { return m_Chunks; } + const std::unordered_map& getChunks() const { return m_WorldData.m_Chunks; } + + DataBuffer SerializeCustom() const; // allow serialisation with invalid World member + void setWorldData(const WorldData& worldData) { m_WorldData = worldData; } }; class UpdateMoneyPacket : public Packet { diff --git a/src/protocol/Protocol.cpp b/src/protocol/Protocol.cpp index 147de0f..23a58a9 100644 --- a/src/protocol/Protocol.cpp +++ b/src/protocol/Protocol.cpp @@ -77,12 +77,12 @@ void PlayerLoginPacket::Deserialize(DataBuffer& data) { data >> m_PlayerName; } -DataBuffer WorldBeginDataPacket::Serialize() const { +DataBuffer WorldBeginDataPacket::SerializeCustom() const { DataBuffer data; - const game::TowerTileColorPalette towerTilePalette = m_World->getTowerTileColorPalette(); - const std::vector& decoTilePalette = m_World->getDecorationPalette(); + const game::TowerTileColorPalette towerTilePalette = m_Header.m_TowerPlacePalette; + const std::vector& decoTilePalette = m_Header.m_DecorationPalette; - data << getID() << towerTilePalette << m_World->getWalkableTileColor() + data << getID() << towerTilePalette << m_Header.m_WalkablePalette << (std::uint16_t)decoTilePalette.size(); // deco color palette @@ -91,57 +91,132 @@ DataBuffer WorldBeginDataPacket::Serialize() const { memcpy((std::uint8_t*)data.data() + bufferSize, decoTilePalette.data(), decoTilePalette.size() * sizeof(game::Color)); - const game::Spawn& redSpawn = m_World->getRedTeam().getSpawn(), blueSpawn = m_World->getBlueTeam().getSpawn(); - const game::TeamCastle& redCastle = m_World->getRedTeam().getCastle(), blueCastle = m_World->getBlueTeam().getCastle(); + 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 << redCastle; data << blueSpawn << blueCastle; // tile palette - data << m_World->getTilePalette().size(); + data << m_Header.m_TilePalette.size(); - for (game::TilePtr tile : m_World->getTilePalette()) { + for (game::TilePtr tile : m_Header.m_TilePalette) { data << tile; } - data << m_World->getSpawnColors(); + 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)); + + 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 << redCastle; + data << blueSpawn << blueCastle; + + // tile palette + data << 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_TowerPlacePalette >> m_WalkablePalette; + data >> m_Header.m_TowerPlacePalette >> m_Header.m_WalkablePalette; std::uint16_t decoPaletteSize; data >> decoPaletteSize; std::size_t decoPalletteSizeByte = decoPaletteSize * sizeof(game::Color); - m_DecorationPalette.reserve(decoPaletteSize); + m_Header.m_DecorationPalette.reserve(decoPaletteSize); - memcpy((void*)m_DecorationPalette.data(), data.data() + data.GetReadOffset(), decoPalletteSizeByte); + memcpy((void*)m_Header.m_DecorationPalette.data(), data.data() + data.GetReadOffset(), decoPalletteSizeByte); data.SetReadOffset(data.GetReadOffset() + decoPalletteSizeByte); - data >> m_RedSpawn >> m_RedTower; - data >> m_BlueSpawn >> m_BlueTower; + data >> m_Header.m_RedSpawn >> m_Header.m_RedCastle; + data >> m_Header.m_BlueSpawn >> m_Header.m_BlueCastle; std::uint64_t tilePaletteSize; data >> tilePaletteSize; - m_TilePalette.reserve(tilePaletteSize); + m_Header.m_TilePalette.reserve(tilePaletteSize); for (std::uint64_t tileNumber = 0; tileNumber < tilePaletteSize; tileNumber++) { game::TilePtr tile; data >> tile; - m_TilePalette.push_back(tile); + m_Header.m_TilePalette.push_back(tile); } - data >> m_SpawnColorPalette; + 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.first << coords.second << (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::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(); @@ -233,7 +308,7 @@ void WorldDataPacket::Deserialize(DataBuffer& data) { } - m_Chunks.insert({ {chunkX, chunkY}, chunk }); + m_WorldData.m_Chunks.insert({ {chunkX, chunkY}, chunk }); } }