diff --git a/include/game/Mobs.h b/include/game/Mobs.h index 4edf40b..24688bf 100644 --- a/include/game/Mobs.h +++ b/include/game/Mobs.h @@ -111,11 +111,13 @@ public: virtual bool OnDeath(World* world) { return true; } + MobID getMobID() const { return m_ID; } const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); } const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); } PlayerID getSender() const { return m_Sender; } MobLevel getLevel() const { return m_Level; } const MobStats* getStats() const { return getMobStats(getType(), m_Level); } + void setHealth(float newHealth) { m_Health = newHealth; } float getHealth() const { return m_Health; } bool isDead() const { return m_Health <= 0; } bool isAlive() const { return m_Health > 0; } diff --git a/include/game/client/WorldClient.h b/include/game/client/WorldClient.h index e16e6bd..8582b77 100644 --- a/include/game/client/WorldClient.h +++ b/include/game/client/WorldClient.h @@ -20,6 +20,8 @@ public: virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet); virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet); virtual void HandlePacket(const protocol::RemoveTowerPacket* packet); + virtual void HandlePacket(const protocol::UpdateMobStatesPacket* packet); + virtual void HandlePacket(const protocol::UpdateCastleLifePacket* packet); }; diff --git a/include/game/server/ServerGame.h b/include/game/server/ServerGame.h index d89b4f2..f09e9c0 100644 --- a/include/game/server/ServerGame.h +++ b/include/game/server/ServerGame.h @@ -13,8 +13,9 @@ class ServerGame : public game::Game, public game::GameListener { private: Server* m_Server; ServerWorld m_ServerWorld; - utils::AutoTimer m_GoldMineTimer{ 1000, std::bind(&ServerGame::updateGoldMines, this) }; - utils::CooldownTimer m_EndGameCooldown{ 1000 * 10 }; + utils::AutoTimer m_GoldMineTimer; + utils::AutoTimer m_MobStatesTimer; + utils::CooldownTimer m_EndGameCooldown; public: ServerGame(Server* server); ~ServerGame() {} @@ -32,6 +33,7 @@ public: virtual void OnGameClose(); private: void balanceTeams(); + void updateMobStates(); void updateGoldMines(); void updatePlayerStats(); }; diff --git a/include/game/server/ServerWorld.h b/include/game/server/ServerWorld.h index dffbcb5..4d67664 100644 --- a/include/game/server/ServerWorld.h +++ b/include/game/server/ServerWorld.h @@ -23,6 +23,8 @@ public: virtual void OnMobDie(game::Mob* mob); + virtual void OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage); + }; } // namespace server diff --git a/include/protocol/PacketHandler.h b/include/protocol/PacketHandler.h index 835a0fd..009bdc0 100644 --- a/include/protocol/PacketHandler.h +++ b/include/protocol/PacketHandler.h @@ -38,6 +38,8 @@ public: virtual void HandlePacket(const RemoveTowerPacket* packet) {} virtual void HandlePacket(const SendMobsPacket* packet) {} virtual void HandlePacket(const UpgradeTowerPacket* packet) {} + virtual void HandlePacket(const UpdateMobStatesPacket* packet) {} + virtual void HandlePacket(const UpdateCastleLifePacket* packet) {} }; } // namespace protocol diff --git a/include/protocol/Protocol.h b/include/protocol/Protocol.h index 6e0a8ba..f1394a4 100644 --- a/include/protocol/Protocol.h +++ b/include/protocol/Protocol.h @@ -33,6 +33,8 @@ enum class PacketType : std::uint8_t { UpdatePlayerTeam, ServerTps, WorldAddTower, + UpdateMobStates, + UpdateCastleLife, // client <--> server KeepAlive, @@ -515,5 +517,60 @@ public: virtual PacketType getType() const { return PacketType::UpgradeTower; } }; +class MobState { + using Point = utils::shape::Point; +private: + game::MobID m_MobID; + Point m_MobPosition; + float m_MobLife; + game::Direction m_MobDirection; +public: + MobState() {} + MobState(game::MobID id, Point position, float life, game::Direction direction) : + m_MobID(id), m_MobPosition(position), m_MobLife(life), m_MobDirection(direction) {} + + game::MobID getMobId() const { return m_MobID; } + Point getMobPosition() const { return m_MobPosition; } + float getMobLife() const { return m_MobLife; } + game::Direction getMobDirection() const { return m_MobDirection; } +}; + +class UpdateMobStatesPacket : public Packet { +private: + std::vector m_MobStates; +public: + UpdateMobStatesPacket() {} + virtual ~UpdateMobStatesPacket() {} + + virtual DataBuffer Serialize() const; + virtual void Deserialize(DataBuffer& data); + virtual void Dispatch(PacketHandler* handler) const; + + void addMobState(MobState mobState) { m_MobStates.push_back(mobState); } + + const std::vector& getMobStates() const { return m_MobStates; } + + virtual PacketType getType() const { return PacketType::UpdateMobStates; } +}; + +class UpdateCastleLifePacket : public Packet { +private: + std::uint16_t m_CastleLife; + game::TeamColor m_Team; +public: + UpdateCastleLifePacket() {} + UpdateCastleLifePacket(std::uint16_t life, game::TeamColor team) : m_CastleLife(life), m_Team(team) {} + virtual ~UpdateCastleLifePacket() {} + + virtual DataBuffer Serialize() const; + virtual void Deserialize(DataBuffer& data); + virtual void Dispatch(PacketHandler* handler) const; + + std::uint16_t getCastleLife() const { return m_CastleLife; } + game::TeamColor getTeamColor() const { return m_Team; } + + virtual PacketType getType() const { return PacketType::UpdateCastleLife; } +}; + } } \ No newline at end of file diff --git a/src/game/client/WorldClient.cpp b/src/game/client/WorldClient.cpp index d7a1a20..6139a6e 100644 --- a/src/game/client/WorldClient.cpp +++ b/src/game/client/WorldClient.cpp @@ -13,13 +13,15 @@ WorldClient::WorldClient(ClientGame* game) : game::World(game), protocol::Packet GetDispatcher()->RegisterHandler(protocol::PacketType::SpawnMob, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this); + GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateCastleLife, this); + GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMobStates, this); } void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) { loadMap(packet); if (m_Game->getGameState() == game::GameState::Game) { const game::Color& backgroundColor = getBackgroundColor(); - m_Game->getRenderer()->setBackgroundColor({ static_cast(backgroundColor.r / 255.0f), static_cast(backgroundColor.g / 255.0f), + m_Game->getRenderer()->setBackgroundColor({ static_cast(backgroundColor.r / 255.0f), static_cast(backgroundColor.g / 255.0f), static_cast(backgroundColor.b / 255.0f) }); } } @@ -53,5 +55,22 @@ void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) { } } +void WorldClient::HandlePacket(const protocol::UpdateMobStatesPacket* packet) { + for (auto mobState : packet->getMobStates()) { + game::MobID mobId = mobState.getMobId(); + auto it = std::find_if(getMobList().begin(), getMobList().end(), [mobId](game::MobPtr mob) { return mob->getMobID() == mobId; }); + if (it != getMobList().end()) { + game::MobPtr& mob = *it; + mob->setCenter(mobState.getMobPosition()); + mob->setDirection(mobState.getMobDirection()); + mob->setHealth(mobState.getMobLife()); + } + } +} + +void WorldClient::HandlePacket(const protocol::UpdateCastleLifePacket* packet) { + getTeam(packet->getTeamColor()).getCastle().setLife(packet->getCastleLife()); +} + } // namespace client } // namespace td diff --git a/src/game/server/ServerGame.cpp b/src/game/server/ServerGame.cpp index 2a1b912..98e96cc 100644 --- a/src/game/server/ServerGame.cpp +++ b/src/game/server/ServerGame.cpp @@ -4,13 +4,17 @@ namespace td { namespace server { -ServerGame::ServerGame(server::Server* server) : game::Game(&m_ServerWorld), m_Server(server), m_ServerWorld(server, this) { +ServerGame::ServerGame(server::Server* server) : game::Game(&m_ServerWorld), m_Server(server), m_ServerWorld(server, this), +m_GoldMineTimer{ 1000, std::bind(&ServerGame::updateGoldMines, this) }, +m_MobStatesTimer{ 5000, std::bind(&ServerGame::updateMobStates, this) }, +m_EndGameCooldown{ 1000 * 10 } { bindListener(this); } void ServerGame::tick(std::uint64_t delta) { if (m_GameState == game::GameState::Game) { Game::tick(delta); + m_MobStatesTimer.update(delta); updatePlayerStats(); } else if (m_GameState == game::GameState::EndGame) { if (m_EndGameCooldown.update(delta)) { @@ -55,6 +59,14 @@ void ServerGame::updateGoldMines() { } } +void ServerGame::updateMobStates() { + protocol::UpdateMobStatesPacket packet; + for (auto mob : m_World->getMobList()) { + packet.addMobState({ mob->getMobID(), mob->getCenter(), mob->getHealth(), mob->getDirection() }); + } + m_Server->broadcastPacket(&packet); +} + void ServerGame::balanceTeams() { for (auto& playerInfo : Game::m_Players) { game::Player& player = playerInfo.second; diff --git a/src/game/server/ServerWorld.cpp b/src/game/server/ServerWorld.cpp index 9b425ec..2e85e5e 100644 --- a/src/game/server/ServerWorld.cpp +++ b/src/game/server/ServerWorld.cpp @@ -66,5 +66,13 @@ void ServerWorld::OnMobDie(game::Mob* mob) { } } +void ServerWorld::OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) { + // calling base class event + World::OnMobCastleDamage(damager, enemyCastle, damage); + + protocol::UpdateCastleLifePacket packet(enemyCastle->getLife(), enemyCastle->getTeam()->getColor()); + m_Server->broadcastPacket(&packet); +} + } // namespace server } // namespace td diff --git a/src/protocol/PacketFactory.cpp b/src/protocol/PacketFactory.cpp index 8a02c07..385b4e5 100644 --- a/src/protocol/PacketFactory.cpp +++ b/src/protocol/PacketFactory.cpp @@ -31,6 +31,8 @@ static std::map packets = { {PacketType::RemoveTower, []() -> PacketPtr {return std::make_unique(); } }, {PacketType::SendMobs, []() -> PacketPtr {return std::make_unique(); } }, {PacketType::UpgradeTower, []() -> PacketPtr {return std::make_unique(); } }, + {PacketType::UpdateCastleLife, []() -> PacketPtr {return std::make_unique(); } }, + {PacketType::UpdateMobStates, []() -> PacketPtr {return std::make_unique(); } }, }; PacketPtr createPacket(PacketType type, DataBuffer& buffer) { diff --git a/src/protocol/Protocol.cpp b/src/protocol/Protocol.cpp index a436cc1..62fce2e 100644 --- a/src/protocol/Protocol.cpp +++ b/src/protocol/Protocol.cpp @@ -535,6 +535,34 @@ void UpgradeTowerPacket::Deserialize(DataBuffer& data) { data >> m_TowerID >> m_TowerLevel; } +DataBuffer UpdateCastleLifePacket::Serialize() const { + DataBuffer data; + data << getID() << m_CastleLife << m_Team; + return data; +} + +void UpdateCastleLifePacket::Deserialize(DataBuffer& data) { + data >> m_CastleLife >> m_Team; +} + +DataBuffer UpdateMobStatesPacket::Serialize() const { + DataBuffer data; + data << getID() << static_cast(m_MobStates.size()); + for (auto mobState : m_MobStates) { + data << mobState; + } + return data; +} + +void UpdateMobStatesPacket::Deserialize(DataBuffer& data) { + std::uint64_t mobCount; + data >> mobCount; + m_MobStates.resize(mobCount); + for (std::uint64_t mobIndex = 0; mobIndex < mobCount; mobIndex++) { + data >> m_MobStates[mobIndex]; + } +} + REGISTER_DISPATCH_CLASS(PlayerLoginPacket); REGISTER_DISPATCH_CLASS(WorldBeginDataPacket); REGISTER_DISPATCH_CLASS(WorldDataPacket); @@ -557,6 +585,8 @@ REGISTER_DISPATCH_CLASS(WorldAddTowerPacket); REGISTER_DISPATCH_CLASS(RemoveTowerPacket); REGISTER_DISPATCH_CLASS(SendMobsPacket); REGISTER_DISPATCH_CLASS(UpgradeTowerPacket); +REGISTER_DISPATCH_CLASS(UpdateCastleLifePacket); +REGISTER_DISPATCH_CLASS(UpdateMobStatesPacket); } // namespace protocol } // namespace td \ No newline at end of file