packed chunk data
This commit is contained in:
@@ -65,7 +65,7 @@ using AllTiles = std::tuple<EmptyTile, TowerTile, WalkableTile, DecorationTile>;
|
|||||||
|
|
||||||
using TileFactory = sp::MessageFactory<Tile, AllTiles>;
|
using TileFactory = sp::MessageFactory<Tile, AllTiles>;
|
||||||
|
|
||||||
class TileHandler : public sp::GenericHandler<AllTiles>{};
|
class TileHandler : public sp::GenericHandler<AllTiles> {};
|
||||||
|
|
||||||
using TilePtr = std::shared_ptr<sp::SerializableMessage<TileFactory>>;
|
using TilePtr = std::shared_ptr<sp::SerializableMessage<TileFactory>>;
|
||||||
|
|
||||||
@@ -79,35 +79,14 @@ typedef std::uint32_t TileIndex;
|
|||||||
// 32 x 32 area
|
// 32 x 32 area
|
||||||
struct Chunk {
|
struct Chunk {
|
||||||
enum { ChunkWidth = 32, ChunkHeight = 32, ChunkSize = ChunkWidth * ChunkHeight };
|
enum { ChunkWidth = 32, ChunkHeight = 32, ChunkSize = ChunkWidth * ChunkHeight };
|
||||||
typedef std::array<std::uint16_t, ChunkSize> ChunkData;
|
using ChunkData = std::array<std::uint16_t, ChunkSize>;
|
||||||
|
using ChunkPackedData = std::vector<uint64_t>;
|
||||||
|
|
||||||
// stores index of tile palette
|
// stores index of tile palette
|
||||||
ChunkData m_Tiles{0};
|
|
||||||
ChunkPalette m_Palette;
|
ChunkPalette m_Palette;
|
||||||
|
ChunkPackedData m_Data;
|
||||||
|
|
||||||
TileIndex GetTileIndex(std::uint16_t tileNumber) const {
|
TileIndex GetTileIndex(std::uint16_t tileNumber) const;
|
||||||
TileIndex chunkPaletteIndex = m_Tiles.at(tileNumber);
|
|
||||||
if (chunkPaletteIndex == 0) // index 0 means empty tile index 1 = first tile
|
|
||||||
return 0;
|
|
||||||
return m_Palette.at(chunkPaletteIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: keep data packed
|
|
||||||
/*
|
|
||||||
std::size_t startLong = static_cast<std::size_t>((tileNumber * bitsPerTile) / BITS_IN_LONG);
|
|
||||||
std::size_t startOffset = static_cast<std::size_t>((tileNumber * bitsPerTile) % BITS_IN_LONG);
|
|
||||||
std::size_t endLong = static_cast<std::size_t>(((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG);
|
|
||||||
|
|
||||||
std::uint64_t value = static_cast<std::uint64_t>(a_Chunk->m_Tiles[tileNumber]);
|
|
||||||
|
|
||||||
value &= individualValueMask;
|
|
||||||
|
|
||||||
chunkData[startLong] |= (value << startOffset);
|
|
||||||
|
|
||||||
if (startLong != endLong) {
|
|
||||||
chunkData[endLong] = (value >> (BITS_IN_LONG - startOffset));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<Chunk> ChunkPtr;
|
typedef std::shared_ptr<Chunk> ChunkPtr;
|
||||||
|
|||||||
@@ -7,13 +7,13 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sp/common/GenericHandler.h>
|
#include <sp/common/GenericHandler.h>
|
||||||
|
#include <sp/io/SerializableMessage.h>
|
||||||
#include <sp/protocol/ConcreteMessage.h>
|
#include <sp/protocol/ConcreteMessage.h>
|
||||||
#include <sp/protocol/MessageDispatcher.h>
|
#include <sp/protocol/MessageDispatcher.h>
|
||||||
#include <sp/protocol/MessageFactory.h>
|
#include <sp/protocol/MessageFactory.h>
|
||||||
#include <td/Types.h>
|
#include <td/Types.h>
|
||||||
#include <td/common/NonCopyable.h>
|
#include <td/common/NonCopyable.h>
|
||||||
#include <td/protocol/command/CommandData.h>
|
#include <td/protocol/command/CommandData.h>
|
||||||
#include <sp/io/SerializableMessage.h>
|
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace protocol {
|
namespace protocol {
|
||||||
|
|||||||
28
src/main.cpp
28
src/main.cpp
@@ -32,6 +32,18 @@ class WorldApply : public td::protocol::PacketHandler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Save(const td::protocol::PacketBase& header, const td::protocol::PacketBase& data) {
|
||||||
|
auto comp = std::make_shared<sp::ZlibCompress>();
|
||||||
|
|
||||||
|
std::ofstream fStream("test/tdmap.tdmap3");
|
||||||
|
auto out = std::make_shared<sp::StdOuput>(fStream);
|
||||||
|
|
||||||
|
sp::MessageStream<td::protocol::PacketFactory> stream(std::move(out), std::move(comp));
|
||||||
|
|
||||||
|
stream.WriteMessage(header);
|
||||||
|
stream.WriteMessage(data);
|
||||||
|
}
|
||||||
|
|
||||||
td::game::World GetWorld() {
|
td::game::World GetWorld() {
|
||||||
auto comp = std::make_shared<sp::ZlibCompress>();
|
auto comp = std::make_shared<sp::ZlibCompress>();
|
||||||
|
|
||||||
@@ -53,23 +65,11 @@ td::game::World GetWorld() {
|
|||||||
d.Dispatch(*header);
|
d.Dispatch(*header);
|
||||||
d.Dispatch(*data);
|
d.Dispatch(*data);
|
||||||
|
|
||||||
|
Save(*header, *data);
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Save(td::protocol::packets::WorldHeaderPacket header, td::protocol::packets::WorldDataPacket data) {
|
|
||||||
auto comp = std::make_shared<sp::ZlibCompress>();
|
|
||||||
|
|
||||||
std::ofstream fStream("test/tdmap.tdmap2");
|
|
||||||
auto out = std::make_shared<sp::StdOuput>(fStream);
|
|
||||||
|
|
||||||
sp::MessageStream<td::protocol::PacketFactory> stream(std::move(out), std::move(comp));
|
|
||||||
|
|
||||||
stream.WriteMessage(header);
|
|
||||||
stream.WriteMessage(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void FastForward(td::game::World& a_World, const td::sim::GameHistory& a_LockSteps) {
|
void FastForward(td::game::World& a_World, const td::sim::GameHistory& a_LockSteps) {
|
||||||
const td::FpFloat delta = td::FpFloat(1) / td::FpFloat(75);
|
const td::FpFloat delta = td::FpFloat(1) / td::FpFloat(75);
|
||||||
for (const auto& lockstep : a_LockSteps) {
|
for (const auto& lockstep : a_LockSteps) {
|
||||||
|
|||||||
@@ -3,7 +3,35 @@
|
|||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
TileIndex Chunk::GetTileIndex(std::uint16_t tileNumber) const {
|
||||||
|
const std::uint8_t bitsPerTile = countBits(m_Palette.size());
|
||||||
|
|
||||||
|
const std::size_t startLong = (tileNumber * bitsPerTile) / BITS_IN_LONG;
|
||||||
|
const std::size_t startOffset = (tileNumber * bitsPerTile) % BITS_IN_LONG;
|
||||||
|
const std::size_t endLong = ((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG;
|
||||||
|
|
||||||
|
const Chunk::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1);
|
||||||
|
|
||||||
|
td::game::Chunk::ChunkData::value_type value;
|
||||||
|
if (startLong == endLong) {
|
||||||
|
value = (m_Data[startLong] >> startOffset);
|
||||||
|
} else {
|
||||||
|
int endOffset = BITS_IN_LONG - startOffset;
|
||||||
|
value = (m_Data[startLong] >> startOffset | m_Data[endLong] << endOffset);
|
||||||
|
}
|
||||||
|
value &= individualValueMask;
|
||||||
|
|
||||||
|
return m_Palette.at(value);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -1,78 +1,18 @@
|
|||||||
#include <td/protocol/packet/PacketSerialize.h>
|
#include <td/protocol/packet/PacketSerialize.h>
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
sp::DataBuffer& operator<<(sp::DataBuffer& a_Buffer, const ChunkPtr& a_Chunk) {
|
sp::DataBuffer& operator<<(sp::DataBuffer& a_Buffer, const ChunkPtr& a_Chunk) {
|
||||||
a_Buffer << a_Chunk->m_Palette;
|
a_Buffer << a_Chunk->m_Palette;
|
||||||
|
a_Buffer << a_Chunk->m_Data;
|
||||||
int bitsPerTile = countBits(a_Chunk->m_Palette.size());
|
return a_Buffer;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
for (unsigned int tileNumber = 0; tileNumber < td::game::Chunk::ChunkSize; tileNumber++) {
|
|
||||||
std::size_t startLong = static_cast<std::size_t>((tileNumber * bitsPerTile) / BITS_IN_LONG);
|
|
||||||
std::size_t startOffset = static_cast<std::size_t>((tileNumber * bitsPerTile) % BITS_IN_LONG);
|
|
||||||
std::size_t endLong = static_cast<std::size_t>(((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG);
|
|
||||||
|
|
||||||
std::uint64_t value = static_cast<std::uint64_t>(a_Chunk->m_Tiles[tileNumber]);
|
|
||||||
|
|
||||||
value &= individualValueMask;
|
|
||||||
|
|
||||||
chunkData[startLong] |= (value << startOffset);
|
|
||||||
|
|
||||||
if (startLong != endLong) {
|
|
||||||
chunkData[endLong] = (value >> (BITS_IN_LONG - startOffset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a_Buffer << chunkData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sp::DataBuffer& operator>>(sp::DataBuffer& a_Buffer, ChunkPtr& a_Chunk) {
|
sp::DataBuffer& operator>>(sp::DataBuffer& a_Buffer, ChunkPtr& a_Chunk) {
|
||||||
a_Chunk = std::make_shared<td::game::Chunk>();
|
a_Chunk = std::make_shared<td::game::Chunk>();
|
||||||
|
|
||||||
a_Buffer >> a_Chunk->m_Palette;
|
a_Buffer >> a_Chunk->m_Palette;
|
||||||
|
return a_Buffer >> a_Chunk->m_Data;
|
||||||
std::uint8_t bitsPerTile = countBits(a_Chunk->m_Palette.size());
|
|
||||||
|
|
||||||
// A bitmask that contains bitsPerTile set bits
|
|
||||||
td::game::Chunk::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1);
|
|
||||||
|
|
||||||
ChunkPackedData chunkData;
|
|
||||||
a_Buffer >> chunkData;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
a_Chunk->m_Tiles[tileNumber] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a_Buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
|
|||||||
Reference in New Issue
Block a user