239 lines
8.0 KiB
C++
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
|