#include "game/server/Server.h" #include "protocol/PacketFactory.h" #include "misc/Format.h" namespace td { namespace server { Server::Server(const std::string& worldFilePath) : m_ServerRunning(false) { m_Game.GetWorld()->LoadMapFromFile(worldFilePath); } Server::~Server() { if (m_Thread.joinable()) m_Thread.join(); } 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)); } } Clean(); }); } void Server::Close() { StopThread(); } void Server::StopThread() { m_ServerRunning = false; } bool Server::Start(std::uint16_t port) { if (!m_Listener.Listen(port, 10)) { utils::LOG(utils::format("Failed to bind port %u !", port)); return false; } if (!m_Listener.SetBlocking(false)) { utils::LOG("Failed to block server socket !"); return false; } utils::LOG(utils::format("Server started at port %u !", port)); m_TickCounter.Reset(); m_ServerRunning = true; StartThread(); return true; } void Server::Clean() { m_Listener.Close(); m_Listener.Destroy(); m_Connections.clear(); GetPlayers().clear(); utils::LOG("Server successfully stopped !"); } void Server::Stop() { if (!m_ServerRunning) return; protocol::DisconnectPacket packet("Server closed"); BroadcastPacket(&packet); StopThread(); } 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