#include #include #include #include #include #include #include namespace td { namespace game { sp::DataBuffer& operator>>(sp::DataBuffer& buffer, game::TilePtr& tile) { game::TileType tileType; buffer >> tileType; switch (tileType) { case game::TileType::Tower: { auto tilePtr = std::make_shared(); buffer >> tilePtr->color_palette_ref >> tilePtr->team_owner; tile = tilePtr; break; } case game::TileType::Walk: { auto tilePtr = std::make_shared(); buffer >> tilePtr->direction; tile = tilePtr; break; } case game::TileType::Decoration: { auto tilePtr = std::make_shared(); buffer >> tilePtr->color_palette_ref; tile = tilePtr; break; } default: break; } return buffer; } } // namespace game } // namespace td namespace sp { namespace details { template <> void ReadMessage(DataBuffer& a_Buffer, td::protocol::pdata::WorldHeader& a_Header) { a_Buffer >> a_Header.m_TowerPlacePalette >> a_Header.m_WalkablePalette; std::uint16_t decoPaletteSize; a_Buffer >> decoPaletteSize; std::size_t decoPalletteSizeByte = decoPaletteSize * sizeof(td::Color); a_Header.m_DecorationPalette.resize(decoPaletteSize); memcpy(reinterpret_cast(a_Header.m_DecorationPalette.data()), a_Buffer.data() + a_Buffer.GetReadOffset(), decoPalletteSizeByte); a_Buffer.SetReadOffset(a_Buffer.GetReadOffset() + decoPalletteSizeByte); a_Buffer >> a_Header.m_Background; td::utils::shape::Rectangle redCastle, blueCastle; a_Buffer >> a_Header.m_RedSpawn >> redCastle; a_Buffer >> a_Header.m_BlueSpawn >> blueCastle; a_Header.m_RedCastle.SetShape(redCastle); a_Header.m_BlueCastle.SetShape(blueCastle); std::uint64_t tilePaletteSize; a_Buffer >> tilePaletteSize; a_Header.m_TilePalette.reserve(tilePaletteSize); for (std::uint64_t tileNumber = 0; tileNumber < tilePaletteSize; tileNumber++) { td::game::TilePtr tile; a_Buffer >> tile; a_Header.m_TilePalette.push_back(tile); } a_Buffer >> a_Header.m_SpawnColorPalette; } typedef std::vector ChunkPackedData; const int BITS_IN_BYTE = 8; const int BITS_IN_LONG = BITS_IN_BYTE * sizeof(std::uint64_t); static unsigned int countBits(unsigned int number) { // log function in base 2 // take only integer part return static_cast(std::log2(number) + 1); } template <> void ReadMessage(DataBuffer& a_Buffer, td::protocol::pdata::WorldData& a_WorldData) { std::uint64_t chunkCount; a_Buffer >> chunkCount; for (std::uint64_t chunkNumber = 0; chunkNumber < chunkCount; chunkNumber++) { td::game::ChunkPtr chunk = std::make_shared(); td::game::ChunkCoord chunkCoords; a_Buffer >> chunkCoords.x >> chunkCoords.y; std::uint64_t chunkPaletteSize; // std::reverse(reinterpret_cast(&chunkPaletteSize), reinterpret_cast(&chunkPaletteSize) + 4); a_Buffer >> chunkPaletteSize; td::game::ChunkPalette chunkPalette(chunkPaletteSize); memcpy(reinterpret_cast(chunkPalette.data()), a_Buffer.data() + a_Buffer.GetReadOffset(), chunkPaletteSize * sizeof(td::game::ChunkPalette::value_type)); a_Buffer.SetReadOffset(a_Buffer.GetReadOffset() + chunkPaletteSize * sizeof(td::game::ChunkPalette::value_type)); chunk->palette = chunkPalette; std::uint8_t bitsPerTile = countBits(chunkPaletteSize); // A bitmask that contains bitsPerTile set bits td::game::Chunk::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1); ChunkPackedData chunkData(td::game::Chunk::ChunkSize / (BITS_IN_BYTE * sizeof(ChunkPackedData::value_type) / bitsPerTile), 0); memcpy(reinterpret_cast(chunkData.data()), a_Buffer.data() + a_Buffer.GetReadOffset(), chunkData.size() * sizeof(ChunkPackedData::value_type)); a_Buffer.SetReadOffset(a_Buffer.GetReadOffset() + chunkData.size() * sizeof(ChunkPackedData::value_type)); for (unsigned int tileNumber = 0; tileNumber < td::game::Chunk::ChunkSize; tileNumber++) { std::size_t startLong = (tileNumber * bitsPerTile) / BITS_IN_LONG; std::size_t startOffset = (tileNumber * bitsPerTile) % BITS_IN_LONG; std::size_t endLong = ((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG; td::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; } a_WorldData.m_Chunks.insert({chunkCoords, chunk}); } } } // namespace details } // namespace sp class WorldApply : public td::protocol::PacketHandler { private: td::game::World& m_World; public: WorldApply(td::game::World& a_World) : m_World(a_World) {} void Handle(const td::protocol::pdata::WorldHeader& a_Header) override { m_World.LoadMap(a_Header); } void Handle(const td::protocol::pdata::WorldData& a_Data) override { m_World.LoadMap(a_Data); } }; int main(int argc, char** argv) { sp::DataBuffer buffer; buffer.ReadFile("test/tdmap.tdmap2"); sp::DataBuffer buffer1 = sp::zlib::Decompress(buffer, 84); buffer.SetReadOffset(buffer.GetReadOffset() + 83); sp::DataBuffer buffer2 = sp::zlib::Decompress(buffer, 511); td::protocol::packets::WorldHeaderPacket header; header.Read(buffer1); td::protocol::packets::WorldDataPacket data; data.Read(buffer2); td::game::World w; WorldApply wa(w); td::protocol::PacketDispatcher d; d.RegisterHandler(td::protocol::PacketID::WorldData, &wa); d.RegisterHandler(td::protocol::PacketID::WorldHeader, &wa); d.Dispatch(header); d.Dispatch(data); td::Display display(1920, 1080, "Tower-Defense 2"); td::render::Camera cam; td::render::RenderPipeline renderer; renderer.AddRenderer(cam, w); cam.SetCamPos({77, 25, 13}); cam.UpdatePerspective(display.GetAspectRatio()); while (!display.IsCloseRequested()) { display.PollEvents(); renderer.Render(); display.Update(); } return 0; }