9 Commits

Author SHA1 Message Date
4bd32e8d0b chore: bump version to alpha-0.4.0 2023-09-02 20:29:51 +02:00
09bba12814 prevent player from joining mid game 2023-09-02 20:27:26 +02:00
bb76e9493f sync player when joining mid game 2023-08-26 11:49:52 +02:00
Simon Pribylski
808ef7b3f6 moved player leave packet 2023-08-26 11:27:05 +02:00
Simon Pribylski
23938a0cb5 fix mob id 2023-08-26 11:21:28 +02:00
Simon Pribylski
5631efcf9e remove mobs on player leave 2023-08-26 10:46:20 +02:00
Simon Pribylski
8e7b446003 add RemoveMobPacket 2023-08-26 10:35:26 +02:00
Simon Pribylski
51ec035490 remove towers on player leave 2023-08-26 10:25:52 +02:00
1f94ae2586 use of SAFE_CHECK 2023-08-15 19:33:09 +02:00
18 changed files with 205 additions and 57 deletions

View File

@@ -20,6 +20,7 @@ public:
virtual void HandlePacket(const protocol::SpawnMobPacket* packet) override;
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override;
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet) override;
virtual void HandlePacket(const protocol::RemoveMobPacket* packet) override;
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateMobStatesPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateCastleLifePacket* packet) override;

View File

@@ -2,7 +2,7 @@
#include "td/misc/DataBuffer.h"
#define TD_VERSION "alpha-0.3.0"
#define TD_VERSION "alpha-0.4.0"
namespace td {
namespace utils {

View File

@@ -35,6 +35,7 @@ public:
virtual void OnGameClose() override;
virtual void OnPlayerJoin(game::PlayerID id) override;
virtual void OnPlayerLeave(game::PlayerID id) override;
private:
void BalanceTeams();
void InitPlayerStats();

View File

@@ -99,7 +99,7 @@ private:
utils::CooldownTimer m_AttackTimer;
public:
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level),
Mob(MobID id, MobLevel level, PlayerID sender) : m_ID(id), m_Sender(sender), m_Level(level),
m_HitCooldown(0), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) {

View File

@@ -174,6 +174,7 @@ public:
void Reset(); // clear mobs and towers
void SpawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir);
MobPtr RemoveMob(MobID id);
TowerPtr PlaceTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder);
TowerPtr RemoveTower(TowerID id);
@@ -219,7 +220,9 @@ public:
const TeamList& GetTeams() const;
TowerList& GetTowers() { return m_Towers; }
const TowerList& GetTowers() const { return m_Towers; }
TowerPtr GetTowerById(TowerID tower);
const Player* GetPlayerById(PlayerID id) const;

View File

@@ -27,6 +27,7 @@ public:
virtual void HandlePacket(const PlayerLeavePacket* packet) {}
virtual void HandlePacket(const PlayerListPacket* packet) {}
virtual void HandlePacket(const PlayerLoginPacket* packet) {}
virtual void HandlePacket(const RemoveMobPacket* packet) {}
virtual void HandlePacket(const RemoveTowerPacket* packet) {}
virtual void HandlePacket(const SelectTeamPacket* packet) {}
virtual void HandlePacket(const SendMobsPacket* packet) {}

View File

@@ -8,6 +8,7 @@
#include "packets/PlayerLeavePacket.h"
#include "packets/PlayerListPacket.h"
#include "packets/PlayerLoginPacket.h"
#include "packets/RemoveMobPacket.h"
#include "packets/RemoveTowerPacket.h"
#include "packets/SelectTeamPacket.h"
#include "packets/SendMobsPacket.h"

View File

@@ -29,6 +29,7 @@ class UpdateCastleLifePacket;
class UpdateMobStatesPacket;
class PlayerBuyItemPacket;
class PlayerBuyMobUpgradePacket;
class RemoveMobPacket;
} // namespace protocol
} // namespace td

View File

@@ -13,7 +13,6 @@ enum class PacketType : std::uint8_t {
// client --> server
PlayerLogin = 0,
SelectTeam,
SpawnMob,
SendMobs,
PlaceTower,
@@ -33,6 +32,8 @@ enum class PacketType : std::uint8_t {
WorldAddTower,
UpdateMobStates,
UpdateCastleLife,
SpawnMob,
RemoveMob,
// client <--> server
KeepAlive,

View File

@@ -0,0 +1,27 @@
#pragma once
#include "td/protocol/Protocol.h"
#include "td/game/BaseGame.h"
namespace td {
namespace protocol {
class RemoveMobPacket : public Packet {
private:
game::MobID m_MobID;
public:
RemoveMobPacket() {}
RemoveMobPacket(game::MobID id) : m_MobID(id) {}
virtual ~RemoveMobPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
game::MobID GetMobID() const { return m_MobID; }
virtual PacketType GetType() const { return PacketType::RemoveMob; }
};
} // namespace protocol
} // namespace td

View File

@@ -8,6 +8,7 @@
#include "td/protocol/packets/WorldDataPacket.h"
#include "td/protocol/packets/SpawnMobPacket.h"
#include "td/protocol/packets/UpgradeTowerPacket.h"
#include "td/protocol/packets/RemoveMobPacket.h"
#include "td/protocol/packets/RemoveTowerPacket.h"
#include "td/protocol/packets/UpdateCastleLifePacket.h"
#include "td/protocol/packets/UpdateMobStatesPacket.h"
@@ -21,6 +22,7 @@ WorldClient::WorldClient(ClientGame* game) : game::World(game), protocol::Packet
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SpawnMob, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveMob, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateCastleLife, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMobStates, this);
@@ -50,7 +52,9 @@ void WorldClient::HandlePacket(const protocol::SpawnMobPacket* packet) {
void WorldClient::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
game::TowerPtr tower = GetTowerById(packet->GetTowerID());
if (tower == nullptr) return; // this should not happen but who knows ?
SAFE_CHECK(tower);
tower->Upgrade(packet->GetTowerLevel().GetLevel(), packet->GetTowerLevel().GetPath());
}
@@ -63,9 +67,17 @@ void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) {
game::TowerPtr tower = RemoveTower(packet->GetTowerID());
if (tower != nullptr) {
GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerRemove, tower);
}
SAFE_CHECK(tower);
GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerRemove, tower);
}
void WorldClient::HandlePacket(const protocol::RemoveMobPacket* packet) {
game::MobPtr mob = RemoveMob(packet->GetMobID());
SAFE_CHECK(mob);
//GetWorldNotifier().NotifyListeners(&MobListener::OnMobDie, mob.get());
}
void WorldClient::HandlePacket(const protocol::UpdateMobStatesPacket* packet) {

View File

@@ -163,12 +163,16 @@ void Server::BroadcastPacket(const protocol::Packet* packet) {
}
void Server::RemoveConnexion(std::uint8_t connexionID) {
std::string playerName = GetGame().GetPlayerById(connexionID)->GetName();
m_Connections.erase(connexionID);
td::game::Player* player = GetGame().GetPlayerById(connexionID);
SAFE_CHECK(player);
std::string playerName = player->GetName();
GetGame().RemovePlayer(connexionID);
m_Connections.erase(connexionID);
m_Lobby.OnPlayerLeave(connexionID);
utils::LOG(utils::format("\t[%s] left !", playerName.c_str()));
OnPlayerLeave(connexionID);
@@ -176,13 +180,10 @@ void Server::RemoveConnexion(std::uint8_t connexionID) {
void Server::OnPlayerJoin(std::uint8_t id) {
m_Lobby.OnPlayerJoin(id);
GetPlayers().insert({ id, game::Player{id} });
}
void Server::OnPlayerLeave(std::uint8_t id) {
protocol::PlayerLeavePacket packet(id);
BroadcastPacket(&packet);
GetGame().NotifyListeners(&game::GameListener::OnPlayerLeave, id);
if (GetPlayers().empty() && m_Game.GetGameState() != game::GameState::Lobby) {
utils::LOG("All players left. Go back to lobby ...");

View File

@@ -13,6 +13,7 @@
#include "td/protocol/packets/RemoveTowerPacket.h"
#include "td/protocol/packets/SelectTeamPacket.h"
#include "td/protocol/packets/SendMobsPacket.h"
#include "td/protocol/packets/SpawnMobPacket.h"
#include "td/protocol/packets/UpdatePlayerTeamPacket.h"
#include "td/protocol/packets/UpdateGameStatePacket.h"
#include "td/protocol/packets/UpgradeTowerPacket.h"
@@ -92,62 +93,94 @@ void ServerConnexion::SendKeepAlive() {
}
void ServerConnexion::HandlePacket(const protocol::PlayerLoginPacket* packet) {
if (m_Player->GetName().empty() && !packet->GetPlayerName().empty()) {
m_Player->SetName(packet->GetPlayerName());
utils::LOG(utils::format("\t[%s] joined !", m_Player->GetName().c_str()));
if (m_Server->GetGame().GetGameState() != game::GameState::Lobby) {
protocol::DisconnectPacket packet("Cannot join during game");
SendPacket(&packet);
protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->GetName());
m_Server->BroadcastPacket(&joinPacket);
CloseConnection();
return;
}
SAFE_CHECK(!packet->GetPlayerName().empty());
std::map<std::uint8_t, protocol::PlayerInfo> playerNames;
for (const auto& pair : m_Server->GetPlayers()) {
const game::Player& player = pair.second;
if (!player.GetName().empty()) {
protocol::PlayerInfo playerInfo;
playerInfo.name = player.GetName();
playerInfo.team = player.GetTeamColor();
playerNames.insert({ player.GetID(), playerInfo });
}
if (!m_Player) { // player does not exist yet
auto playerPos = m_Server->GetPlayers().insert({ m_ID, game::Player{m_ID} });
m_Player = &playerPos.first->second;
}
SAFE_CHECK(m_Player->GetName().empty());
m_Player->SetName(packet->GetPlayerName());
utils::LOG(utils::format("\t[%s] joined !", m_Player->GetName().c_str()));
protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->GetName());
m_Server->BroadcastPacket(&joinPacket);
std::map<std::uint8_t, protocol::PlayerInfo> playerNames;
for (const auto& pair : m_Server->GetPlayers()) {
const game::Player& player = pair.second;
if (!player.GetName().empty()) {
protocol::PlayerInfo playerInfo;
playerInfo.name = player.GetName();
playerInfo.team = player.GetTeamColor();
playerNames.insert({ player.GetID(), playerInfo });
}
}
protocol::PlayerListPacket listPacket(playerNames);
SendPacket(&listPacket);
protocol::PlayerListPacket listPacket(playerNames);
SendPacket(&listPacket);
protocol::UpdateGameStatePacket statePacket(m_Server->GetGame().GetGameState());
SendPacket(&statePacket);
protocol::UpdateGameStatePacket statePacket(m_Server->GetGame().GetGameState());
SendPacket(&statePacket);
m_Server->GetGame().NotifyListeners(&game::GameListener::OnPlayerJoin, m_ID);
protocol::WorldBeginDataPacket headerDataPacket(m_Server->GetGame().GetWorld());
protocol::WorldDataPacket dataPacket(m_Server->GetGame().GetWorld());
SendPacket(&headerDataPacket);
SendPacket(&dataPacket);
m_Server->GetGame().NotifyListeners(&game::GameListener::OnPlayerJoin, m_ID);
protocol::WorldBeginDataPacket headerDataPacket(m_Server->GetGame().GetWorld());
protocol::WorldDataPacket dataPacket(m_Server->GetGame().GetWorld());
SendPacket(&headerDataPacket);
SendPacket(&dataPacket);
// place towers
for (auto tower : m_Server->GetGame().GetWorld()->GetTowers()) {
protocol::WorldAddTowerPacket packet(tower->GetID(), static_cast<std::int32_t>(tower->GetCenterX() - 0.5f),
static_cast<std::int32_t>(tower->GetCenterY() - 0.5f), tower->GetType(), tower->GetBuilder());
SendPacket(&packet);
}
// spawn mobs
for (auto mob : m_Server->GetGame().GetWorld()->GetMobList()) {
protocol::SpawnMobPacket packet(mob->GetMobID(), mob->GetType(), mob->GetLevel(), mob->GetSender(),
mob->GetCenterX(), mob->GetCenterY(), mob->GetDirection());
SendPacket(&packet);
// TODO : update health
}
}
void ServerConnexion::HandlePacket(const protocol::SelectTeamPacket* packet) {
SAFE_CHECK(m_Server->GetGame().GetGameState() == game::GameState::Lobby);
SAFE_CHECK(static_cast<std::int8_t>(packet->GetSelectedTeam()) >= -1 ||
static_cast<std::int8_t>(packet->GetSelectedTeam()) <= 1);
if (static_cast<std::int8_t>(packet->GetSelectedTeam()) >= -1 || static_cast<std::int8_t>(packet->GetSelectedTeam()) <= 1) {
if (m_Player->GetTeamColor() == game::TeamColor::None) { // join a team
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
} else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
m_Player->SetTeamColor(game::TeamColor::None);
} else { // change team
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
}
m_Player->SetTeamColor(packet->GetSelectedTeam());
protocol::UpdatePlayerTeamPacket updateTeamPacket(m_ID, packet->GetSelectedTeam());
m_Server->BroadcastPacket(&updateTeamPacket);
if (m_Player->GetTeamColor() == game::TeamColor::None) { // join a team
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
} else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
m_Player->SetTeamColor(game::TeamColor::None);
} else { // change team
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
}
m_Player->SetTeamColor(packet->GetSelectedTeam());
protocol::UpdatePlayerTeamPacket updateTeamPacket(m_ID, packet->GetSelectedTeam());
m_Server->BroadcastPacket(&updateTeamPacket);
}
void ServerConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
if (packet->GetAliveID() == m_KeepAlive.keepAliveID)
m_KeepAlive.recievedResponse = true;
SAFE_CHECK(packet->GetAliveID() == m_KeepAlive.keepAliveID);
m_KeepAlive.recievedResponse = true;
}
void ServerConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
@@ -156,7 +189,6 @@ void ServerConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
void ServerConnexion::SetServer(Server* server) {
m_Server = server;
m_Player = &m_Server->GetPlayers().at(m_ID);
InitConnection();
SendKeepAlive();
}
@@ -209,8 +241,9 @@ void ServerConnexion::HandlePacket(const protocol::RemoveTowerPacket* packet) {
}
ServerConnexion::~ServerConnexion() {
if (GetDispatcher() != nullptr)
GetDispatcher()->UnregisterHandler(this);
SAFE_CHECK(GetDispatcher() != nullptr);
GetDispatcher()->UnregisterHandler(this);
}
} // namespace server

View File

@@ -2,6 +2,9 @@
#include "server/Server.h"
#include "td/protocol/packets/DisconnectPacket.h"
#include "td/protocol/packets/PlayerLeavePacket.h"
#include "td/protocol/packets/RemoveMobPacket.h"
#include "td/protocol/packets/RemoveTowerPacket.h"
#include "td/protocol/packets/UpdatePlayerTeamPacket.h"
#include "td/protocol/packets/UpdateGameStatePacket.h"
#include "td/protocol/packets/UpdateMoneyPacket.h"
@@ -134,10 +137,41 @@ void ServerGame::OnGameClose() {
m_Server->Restart();
}
void ServerGame::OnPlayerJoin(game::PlayerID id){
void ServerGame::OnPlayerJoin(game::PlayerID id) {
if (m_GameState == game::GameState::Game)
BalanceTeams();
}
void ServerGame::OnPlayerLeave(game::PlayerID playerId) {
// temporary fix
auto& mobList = GetWorld()->GetMobList();
for(std::size_t i = 0; i < mobList.size(); i++) {
auto mob = mobList.at(i);
if(mob->GetSender() == playerId) {
protocol::RemoveMobPacket packet(mob->GetMobID());
m_Server->BroadcastPacket(&packet);
mobList.erase(mobList.begin() + i);
}
}
auto& towerList = GetWorld()->GetTowers();
for(std::size_t i = 0; i < towerList.size(); i++) {
auto tower = towerList.at(i);
if(tower->GetBuilder() == playerId) {
protocol::RemoveTowerPacket packet(tower->GetID());
m_Server->BroadcastPacket(&packet);
towerList.erase(towerList.begin() + i);
}
}
protocol::PlayerLeavePacket packet(playerId);
m_Server->BroadcastPacket(&packet);
}
} // namespace game
} // namespace td

View File

@@ -123,6 +123,17 @@ void World::SpawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID send
GetMobNotifier().NotifyListeners(&MobListener::OnMobSpawn, mob.get());
}
MobPtr World::RemoveMob(MobID mobId) {
auto it = std::find_if(m_Mobs.begin(), m_Mobs.end(), [mobId](MobPtr mob) { return mob->GetMobID() == mobId;});
if (it == m_Mobs.end()) return nullptr;
MobPtr mob = *it;
m_Mobs.erase(it);
return mob;
}
TowerPtr World::PlaceTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) {
TowerPtr tower = TowerFactory::CreateTower(type, id, x, y, builder);
m_Towers.push_back(tower);

View File

@@ -36,6 +36,7 @@ static std::map<PacketType, PacketCreator> packets = {
{PacketType::UpdateMobStates, []() -> PacketPtr {return std::make_unique<UpdateMobStatesPacket>(); } },
{PacketType::PlayerBuyItem, []() -> PacketPtr {return std::make_unique<PlayerBuyItemPacket>(); } },
{PacketType::PlayerBuyMobUpgrade, []() -> PacketPtr {return std::make_unique<PlayerBuyMobUpgradePacket>(); } },
{PacketType::RemoveMob, []() -> PacketPtr {return std::make_unique<RemoveMobPacket>(); } },
};
PacketPtr CreatePacket(PacketType type, DataBuffer& buffer) {

View File

@@ -39,6 +39,7 @@ REGISTER_DISPATCH_CLASS(UpdateCastleLifePacket)
REGISTER_DISPATCH_CLASS(UpdateMobStatesPacket)
REGISTER_DISPATCH_CLASS(PlayerBuyItemPacket)
REGISTER_DISPATCH_CLASS(PlayerBuyMobUpgradePacket)
REGISTER_DISPATCH_CLASS(RemoveMobPacket)
} // namespace protocol
} // namespace td

View File

@@ -0,0 +1,19 @@
#include "td/protocol/packets/RemoveMobPacket.h"
namespace td {
namespace protocol {
DataBuffer RemoveMobPacket::Serialize(bool packetID) const {
DataBuffer data;
WritePacketID(data, packetID);
data << m_MobID;
return data;
}
void RemoveMobPacket::Deserialize(DataBuffer& data) {
data >> m_MobID;
}
} // namespace protocol
} // namespace td