#include "game/server/Server.h" #include #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