212 lines
6.1 KiB
C++
212 lines
6.1 KiB
C++
#include <iostream>
|
|
|
|
#include <sp/common/DataBuffer.h>
|
|
#include <sp/extensions/Compress.h>
|
|
#include <td/input/Display.h>
|
|
|
|
#include <td/game/World.h>
|
|
#include <td/protocol/packet/Packets.h>
|
|
#include <td/render/renderer/WorldRenderer.h>
|
|
|
|
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<game::TowerTile>();
|
|
buffer >> tilePtr->color_palette_ref >> tilePtr->team_owner;
|
|
tile = tilePtr;
|
|
break;
|
|
}
|
|
case game::TileType::Walk: {
|
|
auto tilePtr = std::make_shared<game::WalkableTile>();
|
|
buffer >> tilePtr->direction;
|
|
tile = tilePtr;
|
|
break;
|
|
}
|
|
case game::TileType::Decoration: {
|
|
auto tilePtr = std::make_shared<game::DecorationTile>();
|
|
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<std::uint8_t*>(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<uint64_t> 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<unsigned int>(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::Chunk>();
|
|
|
|
td::game::ChunkCoord chunkCoords;
|
|
a_Buffer >> chunkCoords.x >> chunkCoords.y;
|
|
|
|
std::uint64_t chunkPaletteSize;
|
|
// std::reverse(reinterpret_cast<std::uint8_t*>(&chunkPaletteSize), reinterpret_cast<std::uint8_t*>(&chunkPaletteSize) + 4);
|
|
a_Buffer >> chunkPaletteSize;
|
|
|
|
td::game::ChunkPalette chunkPalette(chunkPaletteSize);
|
|
|
|
memcpy(reinterpret_cast<void*>(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<void*>(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<td::render::WorldRenderer>(cam, w);
|
|
|
|
cam.SetCamPos({77, 25, 13});
|
|
cam.UpdatePerspective(display.GetAspectRatio());
|
|
|
|
while (!display.IsCloseRequested()) {
|
|
display.PollEvents();
|
|
renderer.Render();
|
|
display.Update();
|
|
}
|
|
|
|
return 0;
|
|
}
|