Files
Tower-Defense/src/server/ServerConnexion.cpp

239 lines
8.0 KiB
C++

#include "server/ServerConnexion.h"
#include "td/protocol/PacketDispatcher.h"
#include "td/protocol/PacketFactory.h"
#include "server/Server.h"
#include "td/protocol/packets/ConnectionInfoPacket.h"
#include "td/protocol/packets/DisconnectPacket.h"
#include "td/protocol/packets/KeepAlivePacket.h"
#include "td/protocol/packets/PlaceTowerPacket.h"
#include "td/protocol/packets/PlayerLoginPacket.h"
#include "td/protocol/packets/PlayerJoinPacket.h"
#include "td/protocol/packets/PlayerListPacket.h"
#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"
#include "td/protocol/packets/WorldBeginDataPacket.h"
#include "td/protocol/packets/WorldDataPacket.h"
#include "td/protocol/packets/WorldAddTowerPacket.h"
#include "td/misc/Time.h"
#include "td/misc/Random.h"
#include "td/misc/Format.h"
#include <chrono>
#define KEEP_ALIVE_TIMEOUT 10 * 1000 // 10s
namespace td {
namespace server {
/*
NEVER TRUST USER INPUT
*/
ServerConnexion::ServerConnexion() : m_Player(0) {
}
ServerConnexion::ServerConnexion(network::TCPSocket& socket, std::uint8_t id) : Connexion::Connexion(&m_Dispatcher, socket), m_ID(id), m_Player(0) {
Connexion::UpdateSocket();
}
ServerConnexion::ServerConnexion(ServerConnexion&& move) : Connexion::Connexion(std::move(move)), m_Server(move.m_Server),
m_ID(move.m_ID), m_KeepAlive(move.m_KeepAlive), m_Player(move.m_Player) {
move.m_Server = nullptr;
RegisterHandlers();
}
void ServerConnexion::RegisterHandlers() {
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLogin, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SendMobs, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
}
bool ServerConnexion::UpdateSocket() {
CheckKeepAlive();
return Connexion::UpdateSocket();
}
void ServerConnexion::CheckKeepAlive() {
std::uint64_t time = utils::GetTime();
if (time - m_KeepAlive.sendTime > KEEP_ALIVE_TIMEOUT) {
if (m_KeepAlive.recievedResponse) {
SendKeepAlive();
} else {
protocol::DisconnectPacket packet("Time out");
SendPacket(&packet);
CloseConnection();
}
}
}
void ServerConnexion::SendKeepAlive() {
m_KeepAlive.keepAliveID = utils::GetRandomInt<std::uint64_t>(0, RAND_MAX);
m_KeepAlive.recievedResponse = false;
protocol::KeepAlivePacket keepAlivePacket(m_KeepAlive.keepAliveID);
SendPacket(&keepAlivePacket);
std::uint64_t time = utils::GetTime();
m_KeepAlive.sendTime = time;
}
void ServerConnexion::HandlePacket(const protocol::PlayerLoginPacket* packet) {
SAFE_CHECK(m_Player->GetName().empty() && !packet->GetPlayerName().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::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);
// 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 (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) {
SAFE_CHECK(packet->GetAliveID() == m_KeepAlive.keepAliveID);
m_KeepAlive.recievedResponse = true;
}
void ServerConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
CloseConnection();
}
void ServerConnexion::SetServer(Server* server) {
m_Server = server;
m_Player = &m_Server->GetPlayers().at(m_ID);
InitConnection();
SendKeepAlive();
}
void ServerConnexion::InitConnection() {
protocol::ConnexionInfoPacket conPacket(m_ID);
SendPacket(&conPacket);
}
void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) {
game::TowerType towerType = packet->GetTowerType();
const game::TowerInfo& towerInfo = game::GetTowerInfo(towerType);
server::ServerWorld* world = m_Server->GetGame().GetServerWorld();
Vec2f towerPos = { static_cast<float>(packet->GetTowerX()), static_cast<float>(packet->GetTowerY()) };
SAFE_CHECK(world->CanPlaceLittleTower(towerPos, m_ID));
if (towerInfo.IsBigTower())
SAFE_CHECK(world->CanPlaceBigTower(towerPos, m_ID));
game::TowerPtr tower = world->PlaceTowerAt(towerType, packet->GetTowerX(), packet->GetTowerY(), m_ID);
world->GetWorldNotifier().NotifyListeners(&game::WorldListener::OnTowerAdd, tower);
protocol::WorldAddTowerPacket addTowerPacket(tower->GetID(), packet->GetTowerX(), packet->GetTowerY(), packet->GetTowerType(), m_ID);
m_Server->BroadcastPacket(&addTowerPacket);
}
void ServerConnexion::HandlePacket(const protocol::SendMobsPacket* packet) {
const std::vector<protocol::MobSend>& mobSent = packet->GetMobSends();
//TODO: verify the packet
for (protocol::MobSend mobSend : mobSent) {
m_Server->GetGame().GetServerWorld()->SpawnMobs(mobSend.mobType, mobSend.mobLevel, m_ID, mobSend.mobCount);
}
}
void ServerConnexion::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
//TODO: verify the packet
m_Server->BroadcastPacket(packet);
}
void ServerConnexion::HandlePacket(const protocol::RemoveTowerPacket* packet) {
//TODO: verify the packet
m_Server->BroadcastPacket(packet);
}
ServerConnexion::~ServerConnexion() {
SAFE_CHECK(GetDispatcher() != nullptr);
GetDispatcher()->UnregisterHandler(this);
}
} // namespace server
} // namespace td