Compare commits
2 Commits
c8159bae6e
...
fa663d0481
| Author | SHA1 | Date | |
|---|---|---|---|
|
fa663d0481
|
|||
|
1a455a3d6b
|
@@ -18,9 +18,6 @@ using Vec2fp = Vec2<FpFloat>;
|
||||
|
||||
namespace game {
|
||||
|
||||
|
||||
struct WalkableTile;
|
||||
|
||||
enum class EffectType : std::uint8_t {
|
||||
Slowness = 0,
|
||||
Stun,
|
||||
@@ -127,6 +124,8 @@ class MobListener {
|
||||
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {}
|
||||
};
|
||||
|
||||
using MobList = std::vector<MobPtr>;
|
||||
|
||||
// typedef utils::ObjectNotifier<MobListener> MobNotifier;
|
||||
|
||||
} // namespace game
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <td/Maths.h>
|
||||
#include <td/game/Mobs.h>
|
||||
#include <td/game/Team.h>
|
||||
#include <td/game/Towers.h>
|
||||
|
||||
#include <sp/io/SerializableMessage.h>
|
||||
|
||||
namespace td {
|
||||
namespace game {
|
||||
|
||||
@@ -31,37 +32,44 @@ static constexpr Color RED{255, 0, 0};
|
||||
static constexpr Color GREEN{0, 255, 0};
|
||||
static constexpr Color BLUE{0, 0, 255};
|
||||
|
||||
struct Tile {
|
||||
virtual TileType GetType() const = 0;
|
||||
virtual ~Tile() = default;
|
||||
class TileHandler;
|
||||
|
||||
using Tile = sp::MessageBase<TileType, TileHandler>;
|
||||
|
||||
template <TileType ID, typename TileData>
|
||||
using ConcreteTile = sp::ConcreteMessage<TileData, Tile, ID>;
|
||||
|
||||
namespace data {
|
||||
struct EmptyData {};
|
||||
|
||||
struct TowerTileData {
|
||||
std::uint8_t m_ColorPaletteRef;
|
||||
TeamColor m_TeamOwner;
|
||||
};
|
||||
|
||||
struct TowerTile : Tile {
|
||||
std::uint8_t color_palette_ref;
|
||||
TeamColor team_owner;
|
||||
|
||||
virtual TileType GetType() const {
|
||||
return TileType::Tower;
|
||||
}
|
||||
struct WalkableTileData {
|
||||
Direction m_Direction;
|
||||
};
|
||||
|
||||
struct WalkableTile : Tile {
|
||||
Direction direction;
|
||||
|
||||
virtual TileType GetType() const {
|
||||
return TileType::Walk;
|
||||
}
|
||||
struct DecorationTileData {
|
||||
std::uint16_t m_ColorPaletteRef;
|
||||
};
|
||||
} // namespace data
|
||||
|
||||
struct DecorationTile : Tile {
|
||||
std::uint16_t color_palette_ref;
|
||||
using EmptyTile = ConcreteTile<TileType::None, data::EmptyData>;
|
||||
using TowerTile = ConcreteTile<TileType::Tower, data::TowerTileData>;
|
||||
using WalkableTile = ConcreteTile<TileType::Walk, data::WalkableTileData>;
|
||||
using DecorationTile = ConcreteTile<TileType::Decoration, data::DecorationTileData>;
|
||||
|
||||
virtual TileType GetType() const {
|
||||
return TileType::Decoration;
|
||||
}
|
||||
};
|
||||
using AllTiles = std::tuple<EmptyTile, TowerTile, WalkableTile, DecorationTile>;
|
||||
|
||||
typedef std::shared_ptr<Tile> TilePtr;
|
||||
using TileFactory = sp::MessageFactory<Tile, AllTiles>;
|
||||
|
||||
class TileHandler : public sp::GenericHandler<AllTiles> {};
|
||||
|
||||
using TilePtr = std::shared_ptr<sp::SerializableMessage<TileFactory>>;
|
||||
|
||||
// typedef std::shared_ptr<Tile> TilePtr;
|
||||
typedef std::vector<std::uint16_t> ChunkPalette;
|
||||
|
||||
typedef std::shared_ptr<WalkableTile> WalkableTilePtr;
|
||||
@@ -71,20 +79,14 @@ typedef std::uint32_t TileIndex;
|
||||
// 32 x 32 area
|
||||
struct Chunk {
|
||||
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
|
||||
ChunkData m_Tiles{0};
|
||||
ChunkPalette m_Palette;
|
||||
ChunkPackedData m_Data;
|
||||
|
||||
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
|
||||
TileIndex GetTileIndex(std::uint16_t tileNumber) const;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Chunk> ChunkPtr;
|
||||
@@ -93,17 +95,12 @@ typedef std::array<Color, 2> TowerTileColorPalette;
|
||||
|
||||
typedef std::vector<TilePtr> TilePalette;
|
||||
|
||||
typedef std::vector<MobPtr> MobList;
|
||||
|
||||
typedef std::array<Color, 2> SpawnColorPalette;
|
||||
|
||||
typedef std::vector<TowerPtr> TowerList;
|
||||
|
||||
using ChunkList = std::unordered_map<ChunkCoord, ChunkPtr>;
|
||||
|
||||
sp::DataBuffer& operator>>(sp::DataBuffer& buffer, TilePtr& tile);
|
||||
|
||||
|
||||
} // namespace game
|
||||
|
||||
} // namespace td
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <sp/common/GenericHandler.h>
|
||||
#include <sp/io/SerializableMessage.h>
|
||||
#include <sp/protocol/ConcreteMessage.h>
|
||||
#include <sp/protocol/MessageDispatcher.h>
|
||||
#include <sp/protocol/MessageFactory.h>
|
||||
@@ -32,8 +33,6 @@ class CommandHandler;
|
||||
|
||||
using CommandBase = sp::MessageBase<CommandID, CommandHandler>;
|
||||
|
||||
using CommandPtr = std::unique_ptr<CommandBase>;
|
||||
|
||||
template <typename TData, CommandID ID>
|
||||
using CommandMessage = sp::ConcreteMessage<TData, CommandBase, ID>;
|
||||
|
||||
@@ -61,5 +60,7 @@ using CommandFactory = sp::MessageFactory<CommandBase, AllCommands>;
|
||||
|
||||
using LockStep = std::vector<std::shared_ptr<CommandBase>>;
|
||||
|
||||
using CommandPtr = std::unique_ptr<sp::SerializableMessage<CommandFactory>>;
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace td
|
||||
|
||||
@@ -43,8 +43,5 @@ sp::DataBuffer& operator>>(sp::DataBuffer& a_Buffer, TeamCastle& a_Castle);
|
||||
sp::DataBuffer& operator<<(sp::DataBuffer& a_Buffer, const ChunkPtr& a_Chunk);
|
||||
sp::DataBuffer& operator>>(sp::DataBuffer& a_Buffer, ChunkPtr& a_Chunk);
|
||||
|
||||
sp::DataBuffer& operator<<(sp::DataBuffer& buffer, const TilePtr& tile);
|
||||
sp::DataBuffer& operator>>(sp::DataBuffer& buffer, TilePtr& tile);
|
||||
|
||||
} // namespace game
|
||||
} // namespace td
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <td/game/WorldTypes.h>
|
||||
#include <td/game/Mobs.h>
|
||||
|
||||
namespace td {
|
||||
namespace sim {
|
||||
|
||||
29
src/main.cpp
29
src/main.cpp
@@ -13,7 +13,6 @@
|
||||
#include <sp/common/DataBuffer.h>
|
||||
#include <sp/extensions/Compress.h>
|
||||
#include <sp/io/MessageStream.h>
|
||||
#include <sp/io/MessageSerialize.h>
|
||||
#include <sp/io/StdIo.h>
|
||||
|
||||
class WorldApply : public td::protocol::PacketHandler {
|
||||
@@ -33,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() {
|
||||
auto comp = std::make_shared<sp::ZlibCompress>();
|
||||
|
||||
@@ -54,23 +65,11 @@ td::game::World GetWorld() {
|
||||
d.Dispatch(*header);
|
||||
d.Dispatch(*data);
|
||||
|
||||
Save(*header, *data);
|
||||
|
||||
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) {
|
||||
const td::FpFloat delta = td::FpFloat(1) / td::FpFloat(75);
|
||||
for (const auto& lockstep : a_LockSteps) {
|
||||
|
||||
@@ -5,27 +5,39 @@
|
||||
namespace td {
|
||||
namespace game {
|
||||
|
||||
class ColorTileVisitor : public TileHandler {
|
||||
private:
|
||||
const World& m_World;
|
||||
const Color* m_Result;
|
||||
|
||||
public:
|
||||
ColorTileVisitor(const World& a_World) : m_World(a_World), m_Result(nullptr) {}
|
||||
|
||||
virtual void Handle(const EmptyTile& a_Tile) override {}
|
||||
|
||||
virtual void Handle(const TowerTile& a_Tile) override {
|
||||
m_Result = &m_World.GetTowerTileColorPalette()[a_Tile->m_ColorPaletteRef];
|
||||
}
|
||||
|
||||
virtual void Handle(const WalkableTile& a_Tile) override {
|
||||
m_Result = &m_World.GetWalkableTileColor();
|
||||
}
|
||||
|
||||
virtual void Handle(const DecorationTile& a_Tile) override {
|
||||
m_Result = &m_World.GetDecorationPalette()[a_Tile->m_ColorPaletteRef];
|
||||
}
|
||||
|
||||
const Color* GetResult() {
|
||||
return m_Result;
|
||||
}
|
||||
};
|
||||
|
||||
World::World() : m_CurrentState(std::make_shared<sim::WorldSnapshot>()), m_NextState(m_CurrentState) {}
|
||||
|
||||
const Color* World::GetTileColor(const TilePtr& tile) const {
|
||||
switch (tile->GetType()) {
|
||||
case TileType::Tower: {
|
||||
TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
|
||||
return &m_TowerPlacePalette[towerTile->color_palette_ref];
|
||||
}
|
||||
case TileType::Walk: {
|
||||
return &m_WalkablePalette;
|
||||
}
|
||||
case TileType::Decoration: {
|
||||
DecorationTile* towerTile = dynamic_cast<DecorationTile*>(tile.get());
|
||||
return &m_DecorationPalette[towerTile->color_palette_ref];
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
ColorTileVisitor visitor(*this);
|
||||
tile->Dispatch(visitor);
|
||||
return visitor.GetResult();
|
||||
}
|
||||
|
||||
bool World::LoadMap(const protocol::pdata::WorldHeader& a_WorldHeader) {
|
||||
|
||||
@@ -1,11 +1,37 @@
|
||||
#include <td/game/WorldTypes.h>
|
||||
|
||||
#include <sp/common/DataBuffer.h>
|
||||
|
||||
namespace td {
|
||||
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 td
|
||||
|
||||
@@ -1,78 +1,18 @@
|
||||
#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 game {
|
||||
|
||||
sp::DataBuffer& operator<<(sp::DataBuffer& a_Buffer, const ChunkPtr& a_Chunk) {
|
||||
a_Buffer << a_Chunk->m_Palette;
|
||||
|
||||
int bitsPerTile = countBits(a_Chunk->m_Palette.size());
|
||||
|
||||
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;
|
||||
a_Buffer << a_Chunk->m_Data;
|
||||
return a_Buffer;
|
||||
}
|
||||
|
||||
sp::DataBuffer& operator>>(sp::DataBuffer& a_Buffer, ChunkPtr& a_Chunk) {
|
||||
a_Chunk = std::make_shared<td::game::Chunk>();
|
||||
|
||||
a_Buffer >> a_Chunk->m_Palette;
|
||||
|
||||
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;
|
||||
return a_Buffer >> a_Chunk->m_Data;
|
||||
}
|
||||
|
||||
} // namespace game
|
||||
|
||||
@@ -15,63 +15,5 @@ sp::DataBuffer& operator>>(sp::DataBuffer& a_Buffer, TeamCastle& a_Castle) {
|
||||
return a_Buffer;
|
||||
}
|
||||
|
||||
sp::DataBuffer& operator<<(sp::DataBuffer& buffer, const TilePtr& tile) {
|
||||
buffer << tile->GetType();
|
||||
|
||||
switch (tile->GetType()) {
|
||||
|
||||
case game::TileType::Tower: {
|
||||
const game::TowerTile* towerTile = dynamic_cast<const game::TowerTile*>(tile.get());
|
||||
buffer << towerTile->color_palette_ref << towerTile->team_owner;
|
||||
break;
|
||||
}
|
||||
|
||||
case game::TileType::Walk: {
|
||||
const game::WalkableTile* walkTile = dynamic_cast<const game::WalkableTile*>(tile.get());
|
||||
buffer << walkTile->direction;
|
||||
break;
|
||||
}
|
||||
|
||||
case game::TileType::Decoration: {
|
||||
const game::DecorationTile* decoTile = dynamic_cast<const game::DecorationTile*>(tile.get());
|
||||
buffer << decoTile->color_palette_ref;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
sp::DataBuffer& operator>>(sp::DataBuffer& buffer, 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
|
||||
|
||||
@@ -3,7 +3,7 @@ add_rules("mode.debug", "mode.release")
|
||||
add_repositories("persson-repo https://git.ale-pri.com/Persson-dev/xmake-repo.git")
|
||||
|
||||
add_requires("imgui 1.92.0", {configs = {sdl3 = true, opengl3 = true}})
|
||||
add_requires("splib 2.0.2", "zlib")
|
||||
add_requires("splib 2.1.0", "zlib")
|
||||
add_requires("libsdl3 3.2.16", "glew", "fpm", "enet6")
|
||||
|
||||
set_languages("c++17")
|
||||
|
||||
Reference in New Issue
Block a user