Files
Tower-Defense/src/game/server/Server.cpp
2021-11-21 17:02:42 +01:00

137 lines
3.5 KiB
C++

#include "game/server/Server.h"
#include <iostream>
#include "protocol/PacketFactory.h"
namespace td {
namespace server {
Server::Server(const std::string& worldFilePath) : m_ServerRunning(false) {
m_Game.getWorld()->loadMapFromFile(worldFilePath);
}
void Server::lauchGame() {
m_Game.startGame();
}
void Server::startThread() {
m_Thread = std::thread([this]() {
std::uint64_t lastTime = td::utils::getTime();
while (m_ServerRunning) {
std::uint64_t time = td::utils::getTime();
std::uint64_t delta = time - lastTime;
if (delta >= SERVER_TICK) {
tick(delta);
lastTime = td::utils::getTime();
std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK);
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
}
}
});
}
void Server::stopThread() {
m_ServerRunning = false;
if (m_Thread.joinable())
m_Thread.join();
}
bool Server::start(std::uint16_t port) {
if (!m_Listener.listen(port, 10)) {
std::cout << "Failed to bind port " << port << " !\n";
return false;
}
if (!m_Listener.setBlocking(false)) {
std::cout << "Failed to block server socket !\n";
return false;
}
std::cout << "Server started at port " << port << " !\n";
m_TickCounter.reset();
m_ServerRunning = true;
startThread();
return true;
}
void Server::stop() {
if (!m_ServerRunning)
return;
stopThread();
protocol::DisconnectPacket packet("Server closed");
broadcastPacket(&packet);
m_Listener.close();
m_Listener.destroy();
m_Connections.clear();
getPlayers().clear();
}
void Server::tick(std::uint64_t delta) {
accept();
updateSockets();
m_Lobby.tick();
m_Game.tick(delta);
if (m_TickCounter.update()) {
protocol::ServerTpsPacket packet(m_TickCounter.getTPS(), utils::getTime());
broadcastPacket(&packet);
}
}
void Server::accept() {
static std::uint8_t newPlayerID = 0;
network::TCPSocket newSocket;
if (m_Listener.accept(newSocket)) {
ServerConnexion con(newSocket, newPlayerID);
m_Connections.insert(std::move(ConnexionMap::value_type{ newPlayerID, std::move(con) }));
OnPlayerJoin(newPlayerID);
m_Connections[newPlayerID].setServer(this);
newPlayerID++;
}
}
void Server::updateSockets() {
std::int16_t closedConnexionID = -1;
for (auto& connection : m_Connections) {
ServerConnexion& con = connection.second;
if (con.getSocketStatus() != network::Socket::Status::Connected) {
closedConnexionID = connection.first;
} else {
con.updateSocket();
}
}
if (closedConnexionID != -1) {
removeConnexion(closedConnexionID);
}
}
void Server::broadcastPacket(const protocol::Packet* packet) {
for (auto& connection : m_Connections) {
ServerConnexion& con = connection.second;
con.sendPacket(packet);
}
}
void Server::removeConnexion(std::uint8_t connexionID) {
getPlayers().erase(getPlayers().find(connexionID));
m_Connections.erase(connexionID);
m_Lobby.OnPlayerLeave(connexionID);
OnPlayerLeave(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);
}
} // namespace server
} // namespace td