diff --git a/include/server/Server.h b/include/server/Server.h index f89a88d..c28fb3b 100644 --- a/include/server/Server.h +++ b/include/server/Server.h @@ -63,13 +63,16 @@ private: std::thread m_Thread; bool m_ServerRunning; public: - Server(const std::string& worldFilePath); + Server(); virtual ~Server(); - bool Start(std::uint16_t port); + bool Start(std::uint16_t port, bool blocking); void Stop(); // force the server to stop void Close(); // at the end of a game + bool LoadMap(const std::string& worldFilePath); + bool IsMapLoaded(); + void RemoveConnexion(std::uint8_t connexionID); void BroadcastPacket(const protocol::Packet* packet); @@ -95,6 +98,7 @@ private: void Clean(); void StartThread(); void StopThread(); + void ServerLoop(); void Tick(std::uint64_t delta); void OnPlayerJoin(std::uint8_t id); diff --git a/src/ServerMain.cpp b/src/ServerMain.cpp index 19b89a2..3a9f9f0 100644 --- a/src/ServerMain.cpp +++ b/src/ServerMain.cpp @@ -37,11 +37,55 @@ static void DisplayHelp() { } } -static bool StartServer(const std::string& mapPath, std::uint16_t port) { - td::server::Server server {mapPath}; - return !server.Start(port); +class ConsoleThread { +private: + td::server::Server& m_Server; + std::thread m_Thread; + bool m_Running = true; +public: + ConsoleThread(td::server::Server& server) : m_Server(server) {} + + void Start() { + m_Thread = std::thread([this](){ + std::string line; + while (m_Running) { + getline(std::cin, line); + + if (line == "stop") { + m_Server.Stop(); + } else if (line == "help") { + LOG("use \"stop\" to stop the server"); + } + } + }); + } + + void Stop() { + m_Running = false; + m_Thread.join(); + } + + ~ConsoleThread() {} +}; + +static void StartServer(const std::string& mapPath, std::uint16_t port) { + td::server::Server server; + if (!server.LoadMap(mapPath)) { + exit(EXIT_FAILURE); + } + + ConsoleThread consoleThread{ server }; + consoleThread.Start(); + + if (!server.Start(port, true)) { + exit(EXIT_FAILURE); + } + + LOG("Press Enter to coninue ..."); + consoleThread.Stop(); } + #ifdef __ANDROID__ extern "C" #endif @@ -89,5 +133,7 @@ int main(int argc, const char* args[]) { mapFilePath = arg; } - return StartServer(mapFilePath, port); + StartServer(mapFilePath, port); + + return EXIT_SUCCESS; } \ No newline at end of file diff --git a/src/client/render/gui/MainMenu.cpp b/src/client/render/gui/MainMenu.cpp index ed20e31..d645f7b 100644 --- a/src/client/render/gui/MainMenu.cpp +++ b/src/client/render/gui/MainMenu.cpp @@ -80,8 +80,9 @@ void MainMenu::Render() { bool MainMenu::StartServer() { if (m_WorldFilePath.empty()) return false; - m_Server = std::make_unique(m_WorldFilePath); - if (!m_Server->Start(m_ServerPort)) { + m_Server = std::make_unique(); + m_Server->LoadMap(m_WorldFilePath); + if (!m_Server->Start(m_ServerPort, false)) { return false; } return true; diff --git a/src/server/Server.cpp b/src/server/Server.cpp index bd9e271..bf45976 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -10,8 +10,8 @@ namespace td { namespace server { -Server::Server(const std::string& worldFilePath) : m_ServerRunning(false) { - m_Game.GetWorld()->LoadMapFromFile(worldFilePath); +Server::Server() : m_ServerRunning(false) { + } Server::~Server() { @@ -19,24 +19,36 @@ Server::~Server() { 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]() { - 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(); + ServerLoop(); }); } @@ -48,7 +60,11 @@ void Server::StopThread() { m_ServerRunning = false; } -bool Server::Start(std::uint16_t port) { +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; @@ -60,7 +76,11 @@ bool Server::Start(std::uint16_t port) { utils::LOG(utils::format("Server started at port %u !", port)); m_TickCounter.Reset(); m_ServerRunning = true; - StartThread(); + if (blocking) { + ServerLoop(); + } else { + StartThread(); + } return true; } @@ -145,6 +165,11 @@ void Server::OnPlayerJoin(std::uint8_t id) { void Server::OnPlayerLeave(std::uint8_t id) { protocol::PlayerLeavePacket packet(id); BroadcastPacket(&packet); + + if (GetPlayers().empty()) { + utils::LOG("All players left. Stopping server ..."); + Stop(); + } } } // namespace server