#include "server/Server.h" #include "td/protocol/PacketFactory.h" #include "td/protocol/packets/DisconnectPacket.h" #include "td/protocol/packets/ServerTpsPacket.h" #include "td/protocol/packets/PlayerLeavePacket.h" #include "td/misc/Format.h" namespace td { namespace server { Server::Server() : m_ServerRunning(false) { } Server::~Server() { if (m_Thread.joinable()) m_Thread.join(); } bool Server::LoadMap(const std::string& worldFilePath) { return m_Game.GetWorld()->LoadMapFromFile(worldFilePath); } bool Server::IsMapLoaded() { return !m_Game.GetWorld()->GetTilePalette().empty(); } void Server::ServerLoop() { 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(); m_TickCounter.SetMSPT(lastTime - time); std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK); std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime)); } } Clean(); } void Server::StartThread() { m_Thread = std::thread([this]() { ServerLoop(); }); } void Server::Restart() { m_Game.Reset(); m_Lobby.OpenLobby(); m_Game.NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Lobby); utils::LOG("Game restarted !"); } void Server::Close() { StopThread(); } void Server::StopThread() { m_ServerRunning = false; } bool Server::Start(std::uint16_t port, bool blocking) { if (!IsMapLoaded()) { utils::LOGE(utils::format("No map loaded !")); return false; } if (!m_Listener.Listen(port, 10)) { utils::LOGE(utils::format("Failed to bind port %u !", port)); return false; } if (!m_Listener.SetBlocking(false)) { utils::LOGE("Failed to block server socket !"); return false; } utils::LOG(utils::format("Server started at port %u !", port)); m_TickCounter.Reset(); m_ServerRunning = true; m_Lobby.OpenLobby(); if (blocking) { ServerLoop(); } else { 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(), m_TickCounter.GetMSPT(), 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() { static std::vector closeConnexions; for (auto& connection : m_Connections) { ServerConnexion& con = connection.second; if (con.GetSocketStatus() != network::Socket::Status::Connected) { closeConnexions.push_back(connection.first); } else { con.UpdateSocket(); } } for (auto id : closeConnexions) { RemoveConnexion(id); } closeConnexions.clear(); } 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) { auto it = GetPlayers().find(connexionID); if (it != GetPlayers().end()) GetPlayers().erase(it); 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); if (GetPlayers().empty() && m_Game.GetGameState() != game::GameState::Lobby) { utils::LOG("All players left. Go back to lobby ..."); Restart(); } } } // namespace server } // namespace td