5 Commits

Author SHA1 Message Date
d0b30ba6f8 process tower creation 2025-07-28 14:28:37 +02:00
4f0a81d670 add PredictComma,d 2025-07-28 14:28:29 +02:00
4128b7fbb7 apply steps at the end 2025-07-28 14:28:14 +02:00
47b5a281fc refactor towers 2025-07-28 14:28:03 +02:00
05edb95150 nuke dispatch 2025-07-28 14:27:37 +02:00
7 changed files with 96 additions and 300 deletions

View File

@@ -1,12 +1,16 @@
#pragma once #pragma once
#include <string>
#include <memory> #include <memory>
#include <string>
#include <td/misc/Shapes.h> #include <td/misc/Shapes.h>
#include <td/Types.h> #include <td/Types.h>
#include <sp/common/GenericHandler.h>
#include <sp/protocol/ConcreteMessage.h>
#include <sp/protocol/MessageFactory.h>
namespace td { namespace td {
namespace game { namespace game {
@@ -15,69 +19,66 @@ class Mob;
typedef std::shared_ptr<Mob> MobPtr; typedef std::shared_ptr<Mob> MobPtr;
enum class TowerType : std::uint8_t {
Archer = 0,
Ice,
Sorcerer,
Zeus,
Mage,
Artillery,
Quake,
Poison,
Leach,
Turret,
Necromancer,
TowerCount
};
enum class TowerSize : std::uint8_t { enum class TowerSize : std::uint8_t {
Little = 3, // 3x3 Little = 3, // 3x3
Big = 5, // 5x5 Big = 5, // 5x5
}; };
enum class TowerPath : std::uint8_t { enum class TowerPath : std::uint8_t {
Top = 0, Top = 0,
Base, // Base Path Base, // Base Path
Bottom Bottom
}; };
class TowerStats { class TowerStats {
private: private:
float m_Rate; float m_Rate;
float m_Damage; float m_Damage;
std::uint8_t m_Range; std::uint8_t m_Range;
public:
TowerStats(float rate, float damage, std::uint8_t range) : m_Rate(rate), m_Damage(damage),
m_Range(range) {
}
float GetDamageRate() const { return m_Rate; } public:
float GetDamage() const { return m_Damage; } TowerStats(float rate, float damage, std::uint8_t range) : m_Rate(rate), m_Damage(damage), m_Range(range) {}
std::uint8_t GetRange() const { return m_Range; }
float GetDamageRate() const {
return m_Rate;
}
float GetDamage() const {
return m_Damage;
}
std::uint8_t GetRange() const {
return m_Range;
}
}; };
class TowerLevel { class TowerLevel {
private: private:
// 1, 2, 3, 4 // 1, 2, 3, 4
std::uint8_t m_Level : 3; std::uint8_t m_Level : 3;
// 0 : base path 1 : top path (if there is bottom path) 2 : bottom path (if there is top path) // 0 : base path 1 : top path (if there is bottom path) 2 : bottom path (if there is top path)
TowerPath m_Path : 2; TowerPath m_Path : 2;
public:
public:
TowerLevel() : m_Level(1), m_Path(TowerPath::Base) {} TowerLevel() : m_Level(1), m_Path(TowerPath::Base) {}
TowerLevel(std::uint8_t level, TowerPath path) : m_Level(level), m_Path(path) {} TowerLevel(std::uint8_t level, TowerPath path) : m_Level(level), m_Path(path) {}
std::uint8_t GetLevel() const { return m_Level; } std::uint8_t GetLevel() const {
TowerPath GetPath() const { return m_Path; } return m_Level;
}
TowerPath GetPath() const {
return m_Path;
}
void SetLevel(std::uint8_t level) { m_Level = level; } void SetLevel(std::uint8_t level) {
void SetPath(TowerPath path) { m_Path = path; } m_Level = level;
}
void SetPath(TowerPath path) {
m_Path = path;
}
// operator to sort maps // operator to sort maps
friend bool operator<(const TowerLevel& level, const TowerLevel& other) { friend bool operator<(const TowerLevel& level, const TowerLevel& other) {
return level.GetLevel() + static_cast<std::uint8_t>(level.GetPath()) * 4 < return level.GetLevel() + static_cast<std::uint8_t>(level.GetPath()) * 4 <
other.GetLevel() + static_cast<std::uint8_t>(other.GetPath()) * 4; other.GetLevel() + static_cast<std::uint8_t>(other.GetPath()) * 4;
} }
}; };
@@ -85,182 +86,64 @@ const TowerStats* GetTowerStats(TowerType type, TowerLevel level);
typedef std::uint16_t TowerID; typedef std::uint16_t TowerID;
class Tower : public utils::shape::Circle { class TowerHandler;
private:
class Tower : public utils::shape::Circle, public sp::MessageBase<TowerType, TowerHandler> {
public:
TowerID m_ID; TowerID m_ID;
TowerType m_Type;
TowerLevel m_Level{}; TowerLevel m_Level{};
PlayerID m_Builder; PlayerID m_Builder;
protected:
// utils::CooldownTimer m_Timer; public:
public: Tower() : m_ID(0), m_Level({}), m_Builder(0) {}
Tower(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) : utils::shape::Circle(x + 0.5f, y + 0.5f, 0), m_ID(id), m_Type(type), m_Builder(builder)
// m_Timer(GetStats()->GetDamageRate() * 1000)
{ // converting seconds to millis
SetRadius(GetStats()->GetRange());
}
virtual TowerType GetType() const = 0; virtual TowerType GetType() const = 0;
virtual TowerSize GetSize() const = 0; virtual TowerSize GetSize() const = 0;
virtual void Tick(std::uint64_t delta, World* world) = 0; virtual void Tick(std::uint64_t delta, World* world) = 0;
};
void Upgrade(std::uint8_t level, TowerPath path) { struct TowerData {};
m_Level.SetLevel(level);
m_Level.SetPath(path); template <TowerType Type, TowerSize Size>
// m_Timer.SetCooldown(GetStats()->GetDamageRate() * 1000); // converting seconds to millis class ConcreteTower : public sp::ConcreteMessage<TowerData, Tower, Type, false> {
// m_Timer.Reset(); public:
SetRadius(GetStats()->GetRange()); using HandlerType = typename sp::ConcreteMessage<TowerData, Tower, Type, false>::HandlerType;
virtual TowerSize GetSize() const {
return Size;
} }
std::uint16_t GetID() const { return m_ID; } virtual TowerType GetType() const {
const TowerLevel& GetLevel() const { return m_Level; } return Type;
const TowerStats* GetStats() const { return GetTowerStats(m_Type, m_Level); }
PlayerID GetBuilder() const { return m_Builder; }
bool IsMobInRange(MobPtr mob);
};
typedef std::shared_ptr<Tower> TowerPtr;
namespace TowerFactory {
TowerPtr CreateTower(TowerType type, TowerID id, std::int32_t x, std::int32_t y, PlayerID builder);
std::string GetTowerName(TowerType type);
} // namespace TowerFactory
class TowerInfo {
private:
std::string m_Name, m_Description;
bool m_IsBigTower;
public:
TowerInfo(std::string&& name, std::string&& description, bool big) : m_Name(std::move(name)),
m_Description(std::move(description)), m_IsBigTower(big) {
} }
const std::string& GetName() const { return m_Name; } virtual void Tick(std::uint64_t delta, World* world) {}
const std::string& GetDescription() const { return m_Description; }
bool IsBigTower() const { return m_IsBigTower; } virtual void Dispatch(HandlerType& handler) const override {
handler.Handle(*this);
}
}; };
const TowerInfo& GetTowerInfo(TowerType type); using TowerPtr = std::shared_ptr<Tower>;
// ---------- Little Towers ---------- using ArcherTower = ConcreteTower<TowerType::Archer, TowerSize::Little>;
using ArtilleryTower = ConcreteTower<TowerType::Artillery, TowerSize::Little>;
using IceTower = ConcreteTower<TowerType::Ice, TowerSize::Little>;
using LeachTower = ConcreteTower<TowerType::Leach, TowerSize::Big>;
using MageTower = ConcreteTower<TowerType::Mage, TowerSize::Little>;
using NecromancerTower = ConcreteTower<TowerType::Necromancer, TowerSize::Big>;
using PoisonTower = ConcreteTower<TowerType::Poison, TowerSize::Little>;
using QuakeTower = ConcreteTower<TowerType::Quake, TowerSize::Little>;
using SorcererTower = ConcreteTower<TowerType::Sorcerer, TowerSize::Little>;
using TurretTower = ConcreteTower<TowerType::Turret, TowerSize::Big>;
using ZeusTower = ConcreteTower<TowerType::Zeus, TowerSize::Little>;
class LittleTower : public Tower { using AllTowers = std::tuple<ArcherTower, ArtilleryTower, IceTower, LeachTower, MageTower, NecromancerTower, PoisonTower, QuakeTower,
public: SorcererTower, TurretTower, ZeusTower>;
LittleTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {}
virtual TowerSize GetSize() const { return TowerSize::Little; } using TowerFactory = sp::MessageFactory<Tower, AllTowers>;
virtual TowerType GetType() const = 0; class TowerHandler : public sp::GenericHandler<AllTowers> {};
virtual void Tick(std::uint64_t delta, World* world) = 0;
};
class ArcherTower : public LittleTower { } // namespace game
public: } // namespace td
ArcherTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
constexpr static float ExplosionRadius = 1.5f;
constexpr static float FireDurationSec = 10.0f;
virtual TowerType GetType() const { return TowerType::Archer; }
virtual void Tick(std::uint64_t delta, World* world);
};
class IceTower : public LittleTower {
public:
IceTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Ice; }
virtual void Tick(std::uint64_t delta, World* world);
};
class MageTower : public LittleTower {
public:
MageTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Mage; }
virtual void Tick(std::uint64_t delta, World* world);
};
class PoisonTower : public LittleTower {
public:
PoisonTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Poison; }
virtual void Tick(std::uint64_t delta, World* world);
};
class QuakeTower : public LittleTower {
public:
QuakeTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Quake; }
virtual void Tick(std::uint64_t delta, World* world);
};
class ArtilleryTower : public LittleTower {
public:
ArtilleryTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Artillery; }
virtual void Tick(std::uint64_t delta, World* world);
};
class SorcererTower : public LittleTower {
public:
SorcererTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Sorcerer; }
virtual void Tick(std::uint64_t delta, World* world);
};
class ZeusTower : public LittleTower {
public:
ZeusTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Zeus; }
virtual void Tick(std::uint64_t delta, World* world);
};
// ---------- Big Towers ----------
class BigTower : public Tower {
public:
BigTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {}
virtual TowerSize GetSize() const { return TowerSize::Big; }
virtual TowerType GetType() const = 0;
virtual void Tick(std::uint64_t delta, World* world) = 0;
};
class TurretTower : public BigTower {
public:
TurretTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Turret; }
virtual void Tick(std::uint64_t delta, World* world);
};
class NecromancerTower : public BigTower {
public:
NecromancerTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Necromancer; }
virtual void Tick(std::uint64_t delta, World* world);
};
class LeachTower : public BigTower {
public:
LeachTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
virtual TowerType GetType() const { return TowerType::Leach; }
virtual void Tick(std::uint64_t delta, World* world);
};
} // namespace game
} // namespace td

View File

@@ -1,61 +0,0 @@
#pragma once
/**
* \file PacketDispatcher.h
* \brief File containing the td::protocol::PacketDispatcher class
*/
#include <td/common/NonCopyable.h>
#include <td/protocol/packet/Packets.h>
#include <map>
namespace td {
namespace protocol {
/**
* \class Dispatcher
* \brief Class used to dispatch things
*/
template <typename T_Enum, typename T_Handler, typename T>
class Dispatcher : private NonCopyable {
private:
std::map<T_Enum, std::vector<T_Handler*>> m_Handlers;
public:
/**
* \brief Constructor
*/
Dispatcher() {}
/**
* \brief Dispatch a packet
* \param packet The packet to dispatch
*/
void Dispatch(const T& packet);
/**
* \brief Register a packet handler
* \param type The packet type
* \param handler The packet handler
*/
void RegisterHandler(T_Enum type, T_Handler& handler);
/**
* \brief Unregister a packet handler
* \param type The packet type
* \param handler The packet handler
*/
void UnregisterHandler(T_Enum type, T_Handler& handler);
/**
* \brief Unregister a packet handler
* \param handler The packet handler
*/
void UnregisterHandler(T_Handler& handler);
};
} // namespace protocol
} // namespace td
#include "Dispatcher.inl"

View File

@@ -1,38 +0,0 @@
#pragma once
namespace td {
namespace protocol {
template <typename T_Enum, typename T_Handler, typename T>
void Dispatcher<T_Enum, T_Handler, T>::Dispatch(const T& packet) {
T_Enum type = packet.GetType();
for (auto* handler : m_Handlers[type])
handler->Check(packet);
}
template <typename T_Enum, typename T_Handler, typename T>
void Dispatcher<T_Enum, T_Handler, T>::RegisterHandler(T_Enum type, T_Handler& handler) {
auto found = std::find(m_Handlers[type].begin(), m_Handlers[type].end(), &handler);
if (found == m_Handlers[type].end())
m_Handlers[type].push_back(&handler);
}
template <typename T_Enum, typename T_Handler, typename T>
void Dispatcher<T_Enum, T_Handler, T>::UnregisterHandler(T_Enum type, T_Handler& handler) {
m_Handlers[type].erase(std::remove(m_Handlers[type].begin(), m_Handlers[type].end(), &handler), m_Handlers[type].end());
}
template <typename T_Enum, typename T_Handler, typename T>
void Dispatcher<T_Enum, T_Handler, T>::UnregisterHandler(T_Handler& handler) {
for (auto& pair : m_Handlers) {
if (pair.second.empty())
continue;
PacketType type = pair.first;
m_Handlers[type].erase(std::remove(m_Handlers[type].begin(), m_Handlers[type].end(), &handler), m_Handlers[type].end());
}
}
} // namespace protocol
} // namespace td

View File

@@ -43,6 +43,11 @@ struct PlayerLeave {
PlayerID m_PlayerId; PlayerID m_PlayerId;
}; };
struct PredictCommand {
std::unique_ptr<CommandBase> m_Command;
std::uint16_t m_FrameNumber;
};
/** Keep alive */ /** Keep alive */
struct KeepAlive { struct KeepAlive {
std::uint64_t m_KeepAliveId; std::uint64_t m_KeepAliveId;

View File

@@ -27,6 +27,7 @@ enum class PacketID : std::uint8_t {
PlayerJoin, PlayerJoin,
PlayerLeave, PlayerLeave,
PlayerLogin, PlayerLogin,
PredictCommand,
WorldHeader, WorldHeader,
WorldData, WorldData,
}; };
@@ -51,15 +52,15 @@ using LoggingSuccessPacket = PacketMessage<pdata::LoggingSuccess, PacketID::Logg
using PlayerJoinPacket = PacketMessage<pdata::PlayerJoin, PacketID::PlayerJoin>; using PlayerJoinPacket = PacketMessage<pdata::PlayerJoin, PacketID::PlayerJoin>;
using PlayerLeavePacket = PacketMessage<pdata::PlayerLeave, PacketID::PlayerLeave>; using PlayerLeavePacket = PacketMessage<pdata::PlayerLeave, PacketID::PlayerLeave>;
using PlayerLoginPacket = PacketMessage<pdata::PlayerLogin, PacketID::PlayerLogin>; using PlayerLoginPacket = PacketMessage<pdata::PlayerLogin, PacketID::PlayerLogin>;
using PredictCommandPacket = PacketMessage<pdata::PredictCommand, PacketID::PredictCommand>;
using WorldHeaderPacket = PacketMessage<pdata::WorldHeader, PacketID::WorldHeader>; using WorldHeaderPacket = PacketMessage<pdata::WorldHeader, PacketID::WorldHeader>;
using WorldDataPacket = PacketMessage<pdata::WorldData, PacketID::WorldData>; using WorldDataPacket = PacketMessage<pdata::WorldData, PacketID::WorldData>;
} // namespace packets } // namespace packets
using AllPackets = std::tuple<packets::BeginGamePacket, packets::ChatMessagePacket, packets::DisconnectPacket, using AllPackets = std::tuple<packets::BeginGamePacket, packets::ChatMessagePacket, packets::DisconnectPacket,
packets::KeepAlivePacket, packets::LockStepsPacket, packets::LoggingSuccessPacket, packets::PlayerJoinPacket, packets::KeepAlivePacket, packets::LockStepsPacket, packets::LoggingSuccessPacket, packets::PlayerJoinPacket,
packets::PlayerLeavePacket, packets::PlayerLoginPacket, packets::WorldHeaderPacket, packets::WorldDataPacket>; packets::PlayerLeavePacket, packets::PlayerLoginPacket, packets::PredictCommandPacket, packets::WorldHeaderPacket, packets::WorldDataPacket>;
class PacketHandler : public sp::GenericHandler<AllPackets> {}; class PacketHandler : public sp::GenericHandler<AllPackets> {};

View File

@@ -6,9 +6,17 @@ namespace sim {
CommandApply::CommandApply(const game::World& a_World, WorldSnapshot& a_Snapshot) : m_World(a_World), m_Snapshot(a_Snapshot) {} CommandApply::CommandApply(const game::World& a_World, WorldSnapshot& a_Snapshot) : m_World(a_World), m_Snapshot(a_Snapshot) {}
void CommandApply::Handle(const protocol::commands::EndCommand& a_End) {} void CommandApply::Handle(const protocol::commands::EndCommand& a_End) {}
void CommandApply::Handle(const protocol::commands::PlaceTowerCommand& a_PlaceTower) { void CommandApply::Handle(const protocol::commands::PlaceTowerCommand& a_PlaceTower) {
m_World.CanPlaceBigTower({}, 0); static game::TowerFactory factory;
auto tower = std::shared_ptr<game::Tower>(factory.CreateMessage(*a_PlaceTower->m_Type).release());
tower->m_Builder = *a_PlaceTower->m_Placer;
tower->SetCenter(utils::shape::Point(a_PlaceTower->m_Position.x, a_PlaceTower->m_Position.y));
m_Snapshot.m_Towers.push_back(tower);
} }
void CommandApply::Handle(const protocol::commands::PlayerJoinCommand& a_PlayerJoin) {} void CommandApply::Handle(const protocol::commands::PlayerJoinCommand& a_PlayerJoin) {}
void CommandApply::Handle(const protocol::commands::SpawnTroopCommand& a_SpawnTroop) { void CommandApply::Handle(const protocol::commands::SpawnTroopCommand& a_SpawnTroop) {

View File

@@ -3,8 +3,6 @@
#include <td/simulation/system/EntityMove.h> #include <td/simulation/system/EntityMove.h>
#include <td/simulation/CommandApply.h> #include <td/simulation/CommandApply.h>
#define ADD_SYSTEM(class) std::move(std::make_unique<class>())
namespace td { namespace td {
namespace sim { namespace sim {
@@ -15,8 +13,8 @@ WorldTicker::WorldTicker() {
WorldSnapshot WorldTicker::NextStep( WorldSnapshot WorldTicker::NextStep(
const game::World& a_World, WorldSnapshot& a_PreviousState, const protocol::LockStep& a_LockStep, FpFloat a_Delta) { const game::World& a_World, WorldSnapshot& a_PreviousState, const protocol::LockStep& a_LockStep, FpFloat a_Delta) {
WorldSnapshot next = CreateNext(a_PreviousState); WorldSnapshot next = CreateNext(a_PreviousState);
ApplySteps(a_World, next, a_LockStep); // maybe swap with tick ?
Tick(a_World, next, a_Delta); Tick(a_World, next, a_Delta);
ApplySteps(a_World, next, a_LockStep);
return next; return next;
} }