From 2fc0f28b271740e64ed43b96ca12cf454cea3472 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Thu, 4 Nov 2021 11:01:46 +0100 Subject: [PATCH] refactor: create MainMenu and GameMenu classes --- include/game/server/Lobby.h | 3 + include/game/server/Server.h | 12 +- include/render/gui/GameMenu.h | 24 ++++ include/render/gui/MainMenu.h | 37 ++++++ src/game/server/Lobby.cpp | 4 +- src/game/server/Server.cpp | 33 +++++- src/render/gui/GameMenu.cpp | 104 +++++++++++++++++ src/render/gui/MainMenu.cpp | 84 ++++++++++++++ src/render/gui/TowerGui.cpp | 207 ++-------------------------------- 9 files changed, 303 insertions(+), 205 deletions(-) create mode 100644 include/render/gui/GameMenu.h create mode 100644 include/render/gui/MainMenu.h create mode 100644 src/render/gui/GameMenu.cpp create mode 100644 src/render/gui/MainMenu.cpp diff --git a/include/game/server/Lobby.h b/include/game/server/Lobby.h index 9ccd13a..179682d 100644 --- a/include/game/server/Lobby.h +++ b/include/game/server/Lobby.h @@ -25,6 +25,9 @@ public: void sendTimeRemaining(); void tick(); + + //static constexpr int LobbyWaitingTime = 2 * 60 * 1000; // in millis + static constexpr int LobbyWaitingTime = 5 * 1000; // in millis }; } // namespace server diff --git a/include/game/server/Server.h b/include/game/server/Server.h index cfc2a02..5c6fdff 100644 --- a/include/game/server/Server.h +++ b/include/game/server/Server.h @@ -2,6 +2,7 @@ #include #include +#include #include "network/TCPListener.h" #include "protocol/Protocol.h" @@ -11,9 +12,6 @@ #include "ServerConnexion.h" #include "Lobby.h" -//#define LOBBY_WAITING_TIME 2 * 60 * 1000 -#define LOBBY_WAITING_TIME 5 * 1000 - #define SERVER_TPS 20 #define SERVER_TICK 1000 / SERVER_TPS @@ -58,12 +56,14 @@ private: ServerGame m_Game{ this }; Lobby m_Lobby{ this }; TickCounter m_TickCounter; + + std::thread m_Thread; + bool m_ServerRunning; public: Server(const std::string& worldFilePath); virtual ~Server() {} bool start(std::uint16_t port); - void tick(std::uint64_t delta); void stop(); void lauchGame(); @@ -88,6 +88,10 @@ private: void accept(); void updateSockets(); + void startThread(); + void stopThread(); + void tick(std::uint64_t delta); + void OnPlayerJoin(std::uint8_t id); void OnPlayerLeave(std::uint8_t id); }; diff --git a/include/render/gui/GameMenu.h b/include/render/gui/GameMenu.h new file mode 100644 index 0000000..2c64e7b --- /dev/null +++ b/include/render/gui/GameMenu.h @@ -0,0 +1,24 @@ +#pragma once + +#include "SummonMenu.h" + +namespace td { +namespace gui { + +class GameMenu : public GuiWidget { +private: + std::unique_ptr m_SummonMenu; +public: + GameMenu(client::Client* client); + + virtual void render(); +private: + void showTPS(); + void showStats(); + void showPlayers(); + void showLobbyProgress(); + void showTeamSelection(); +}; + +} // namespace gui +} // namespace td diff --git a/include/render/gui/MainMenu.h b/include/render/gui/MainMenu.h new file mode 100644 index 0000000..adf99fc --- /dev/null +++ b/include/render/gui/MainMenu.h @@ -0,0 +1,37 @@ +#pragma once + +#include "GuiWidget.h" + +#include "render/gui/imgui/imgui_filebrowser.h" + +#include "game/server/Server.h" + +#include + +namespace td { +namespace gui { + +class MainMenu : public GuiWidget { +private: + bool m_TriedToConnect = false; + bool m_TriedToCreate = false; + std::string m_ConnectAddress; + int m_ConnectPort; + int m_ServerPort = 25565; + std::string m_WorldFilePath; + imgui_addons::ImGuiFileBrowser m_FileDialog; + + std::unique_ptr m_Server; +public: + MainMenu(client::Client* client); + ~MainMenu(); + + virtual void render(); + + const server::Server* getServer() const { return m_Server.get(); } +private: + bool startServer(); +}; + +} // namespace gui +} // namespace td diff --git a/src/game/server/Lobby.cpp b/src/game/server/Lobby.cpp index 9985b18..31d0094 100644 --- a/src/game/server/Lobby.cpp +++ b/src/game/server/Lobby.cpp @@ -36,7 +36,7 @@ void Lobby::tick() { if (m_GameStarted || m_StartTimerTime == 0) return; - if (utils::getTime() - m_StartTimerTime >= LOBBY_WAITING_TIME) { + if (utils::getTime() - m_StartTimerTime >= LobbyWaitingTime) { protocol::UpdateGameStatePacket packet(game::GameState::Game); m_Server->broadcastPacket(&packet); m_GameStarted = true; @@ -48,7 +48,7 @@ void Lobby::tick() { } void Lobby::sendTimeRemaining() { - protocol::UpdateLobbyTimePacket packet(LOBBY_WAITING_TIME - (utils::getTime() - m_StartTimerTime)); // converting second to millis + protocol::UpdateLobbyTimePacket packet(LobbyWaitingTime - (utils::getTime() - m_StartTimerTime)); // converting second to millis m_Server->broadcastPacket(&packet); } diff --git a/src/game/server/Server.cpp b/src/game/server/Server.cpp index 848132e..e5bc8a6 100644 --- a/src/game/server/Server.cpp +++ b/src/game/server/Server.cpp @@ -5,7 +5,7 @@ namespace td { namespace server { -Server::Server(const std::string& worldFilePath) { +Server::Server(const std::string& worldFilePath) : m_ServerRunning(false) { m_Game.getWorld()->loadMapFromFile(worldFilePath); } @@ -13,6 +13,31 @@ 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"; @@ -24,10 +49,16 @@ bool Server::start(std::uint16_t port) { } 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); diff --git a/src/render/gui/GameMenu.cpp b/src/render/gui/GameMenu.cpp new file mode 100644 index 0000000..46a7a60 --- /dev/null +++ b/src/render/gui/GameMenu.cpp @@ -0,0 +1,104 @@ +#include "render/gui/GameMenu.h" +#include "render/gui/imgui/imgui.h" + +#include "game/client/Client.h" +#include "game/server/Lobby.h" + +namespace td { +namespace gui { + +ImVec4 getImGuiTeamColor(td::game::TeamColor color) { + switch (color) { + case td::game::TeamColor::None: + break; + case td::game::TeamColor::Red: + return ImVec4(1, 0, 0, 1); + case td::game::TeamColor::Blue: + return ImVec4(0, 0, 1, 1); + } + return ImVec4(1, 1, 1, 1); +} + +GameMenu::GameMenu(client::Client* client) : GuiWidget(client), m_SummonMenu(std::make_unique(client)) { + +} + +void GameMenu::render(){ + if (getClient()->getGame().getGameState() == td::game::GameState::Lobby) { + ImGui::Begin("Lobby"); + + showTPS(); + showPlayers(); + showLobbyProgress(); + showTeamSelection(); + + ImGui::End(); + } + if (getClient()->getGame().getGameState() == td::game::GameState::Game) { + ImGui::Begin("Game"); + + showTPS(); + showStats(); + showPlayers(); + + ImGui::End(); + + m_SummonMenu->render(); + } +} + +void GameMenu::showPlayers() { + if (ImGui::TreeNode(std::string("Players (" + std::to_string(getClient()->getGame().getPlayers().size()) + ")##player_list").c_str())) { + for (auto pair : getClient()->getGame().getPlayers()) { + const td::game::Player& player = pair.second; + ImGui::PushStyleColor(ImGuiCol_Text, getImGuiTeamColor(player.getTeamColor())); + ImGui::Text("%s", player.getName().c_str()); + ImGui::PopStyleColor(); + } + ImGui::TreePop(); + } +} + +void GameMenu::showTeamSelection() { + if (getClient()->getGame().getPlayer() == nullptr) + return; + td::game::TeamColor playerTeam = getClient()->getGame().getPlayer()->getTeamColor(); + + if (ImGui::Button(std::string((playerTeam == td::game::TeamColor::Red ? "Leave" : "Join") + std::string(" Red Team")).c_str())) { + if (playerTeam == td::game::TeamColor::Red) + getClient()->selectTeam(td::game::TeamColor::None); + else + getClient()->selectTeam(td::game::TeamColor::Red); + } + ImGui::SameLine(); + if (ImGui::Button(std::string((playerTeam == td::game::TeamColor::Blue ? "Leave" : "Join") + std::string(" Blue Team")).c_str())) { + if (playerTeam == td::game::TeamColor::Blue) + getClient()->selectTeam(td::game::TeamColor::None); + else + getClient()->selectTeam(td::game::TeamColor::Blue); + } +} + +void GameMenu::showLobbyProgress() { + const int timePassed = server::Lobby::LobbyWaitingTime - getClient()->getGame().getLobbyTime(); + const float progress = (float)timePassed / (float)(server::Lobby::LobbyWaitingTime); + if (progress > 0 && progress < 1) { + ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f), std::string(std::to_string(getClient()->getGame().getLobbyTime() / 1000) + "s").c_str()); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Text("Time Remaining"); + } else { + ImGui::Text("Waiting for players ...\n"); + } +} + +void GameMenu::showTPS() { + ImGui::Text("Server TPS : %.1f", getClient()->getConnexion().getServerTPS()); + ImGui::Text("Server Ping : %i", getClient()->getConnexion().getServerPing()); +} + +void GameMenu::showStats() { + ImGui::Text("Gold : %i", getClient()->getGame().getPlayer()->getGold()); +} + +} // namespace gui +} // namespace td diff --git a/src/render/gui/MainMenu.cpp b/src/render/gui/MainMenu.cpp new file mode 100644 index 0000000..54bd569 --- /dev/null +++ b/src/render/gui/MainMenu.cpp @@ -0,0 +1,84 @@ +#include "render/gui/MainMenu.h" + +#include "game/client/Client.h" + +#include "game/server/Server.h" + +namespace td { +namespace gui { + +MainMenu::MainMenu(client::Client* client) : GuiWidget(client) { + m_ConnectAddress.reserve(256); +} + +MainMenu::~MainMenu(){ + if(m_Server != nullptr) + m_Server->stop(); +} + +void MainMenu::render() { + ImGui::Begin("Main Menu"); + if (ImGui::Button("Rejoindre une partie##join")) { + ImGui::OpenPopup("Rejoindre une partie##join_popup"); + } + if (ImGui::Button("Créer une partie")) { + ImGui::OpenPopup("Créer une partie##create_popup"); + } + if (ImGui::Button("Options")) { + // TODO: add settings + } + + if (ImGui::BeginPopup("Rejoindre une partie##join_popup")) { + ImGui::InputText("Server Adress", &m_ConnectAddress.front(), m_ConnectAddress.capacity()); + ImGui::InputInt("Port", &m_ConnectPort, -1); + if (ImGui::Button("Rejoindre")) { + getClient()->connect(td::network::Dns::Resolve(m_ConnectAddress), m_ConnectPort); + m_TriedToConnect = true; + } + if (m_TriedToConnect) { + ImGui::Text("Impossible de se connecter"); + } + ImGui::EndPopup(); + } else { + m_TriedToConnect = false; + } + + if (ImGui::BeginPopup("Créer une partie##create_popup")) { + ImGui::InputInt("Server Port", &m_ServerPort, -1); + ImGui::Text("%s", std::string("Fichier de monde sélectionné : " + (m_WorldFilePath.empty() ? std::string("Aucun") : m_WorldFilePath)).c_str()); + ImGui::SameLine(); + if (ImGui::Button("Ouvrir un fichier")) { + ImGui::OpenPopup("WorldFileDialog"); + } + if (m_FileDialog.showFileDialog("WorldFileDialog", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(600, 300), ".tdmap")) { + m_WorldFilePath = m_FileDialog.selected_path; + } + if (ImGui::Button("Créer")) { + if (!startServer()) { + m_TriedToCreate = true; + } else { + getClient()->connect(td::network::Dns::Resolve("localhost"), m_ServerPort); + } + } + if (m_TriedToCreate) + ImGui::Text("Failed to launch server"); + ImGui::EndPopup(); + } else { + m_TriedToConnect = false; + } + + ImGui::End(); +} + +bool MainMenu::startServer(){ + if (m_WorldFilePath.empty()) + return false; + m_Server = std::make_unique(m_WorldFilePath); + if (!m_Server->start(m_ServerPort)) { + return false; + } + return true; +} + +} // namespace gui +} // namespace td diff --git a/src/render/gui/TowerGui.cpp b/src/render/gui/TowerGui.cpp index 6c27949..f110434 100644 --- a/src/render/gui/TowerGui.cpp +++ b/src/render/gui/TowerGui.cpp @@ -7,6 +7,7 @@ #include "render/gui/TowerGui.h" #include "render/gui/imgui/imgui.h" +#include "render/gui/imgui/imgui_filebrowser.h" #include "imgui/imgui_impl_opengl3.h" #include "imgui/imgui_impl_sdl.h" #include @@ -14,12 +15,11 @@ #include "game/client/Client.h" #include "game/server/Server.h" #include "misc/Time.h" -#include "imgui/imgui_filebrowser.h" #include "render/Renderer.h" #include "network/Network.h" -#include "render/gui/GuiManager.h" -#include "render/gui/SummonMenu.h" +#include "render/gui/MainMenu.h" +#include "render/gui/GameMenu.h" #include #include @@ -31,12 +31,14 @@ static SDL_GLContext gl_context; static std::unique_ptr client; static std::thread* serverThread; static td::render::Renderer* renderer; -static td::gui::GuiManager guiManager; +static std::unique_ptr mainMenu; +static std::unique_ptr gameMenu; bool serverShouldStop = false; void initWidgets(){ - guiManager.addWidgets(std::make_shared(client.get())); + mainMenu = std::make_unique(client.get()); + gameMenu = std::make_unique(client.get()); } void init(SDL_Window* sdl_window, SDL_GLContext sdlContext, td::render::Renderer* render) { @@ -81,197 +83,6 @@ void renderFPSCounter() { ImGui::End(); } -bool startServer(int port, const std::string& worldFilePath) { - if (worldFilePath.empty()) - return false; - std::shared_ptr server = std::make_shared(worldFilePath); - if (!server->start(port)) { - return false; - } - serverThread = new std::thread([server]() { - while (!serverShouldStop) { - static std::uint64_t lastTime = td::utils::getTime(); - std::uint64_t time = td::utils::getTime(); - - std::uint64_t delta = time - lastTime; - - if (delta >= SERVER_TICK) { - server->tick(delta); - lastTime = td::utils::getTime(); - std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK); - std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime)); - } - - } - server->stop(); - }); - return true; -} - -void renderMainMenu() { - ImGui::Begin("Main Menu"); - if (ImGui::Button("Rejoindre une partie##join")) { - ImGui::OpenPopup("Rejoindre une partie##join_popup"); - } - if (ImGui::Button("Créer une partie")) { - ImGui::OpenPopup("Créer une partie##create_popup"); - } - if (ImGui::Button("Options")) { - - } - static bool triedToConnect = false; - if (ImGui::BeginPopup("Rejoindre une partie##join_popup")) { - static char buffer[512] = "localhost"; - static int port = 25565; - ImGui::InputText("Server Adress", buffer, sizeof(buffer)); - ImGui::InputInt("Port", &port, -1); - if (ImGui::Button("Rejoindre")) { - client->connect(td::network::Dns::Resolve(buffer), port); - triedToConnect = true; - } - if (triedToConnect) { - ImGui::Text("Impossible de se connecter"); - } - ImGui::EndPopup(); - } else { - triedToConnect = false; - } - - static bool triedToCreate = false; - if (ImGui::BeginPopup("Créer une partie##create_popup")) { - static imgui_addons::ImGuiFileBrowser file_dialog; - static int port = 25565; - static std::string worldFilePath; - - ImGui::InputInt("Server Port", &port, -1); - ImGui::Text("%s", std::string("Fichier de monde sélectionné : " + (worldFilePath.empty() ? std::string("Aucun") : worldFilePath)).c_str()); - ImGui::SameLine(); - if (ImGui::Button("Ouvrir un fichier")) { - ImGui::OpenPopup("WorldFileDialog"); - } - if (file_dialog.showFileDialog("WorldFileDialog", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(600, 300), ".tdmap")) { - worldFilePath = file_dialog.selected_path; - } - if (ImGui::Button("Créer")) { - if (!startServer(port, worldFilePath)) { - triedToCreate = true; - } else { - client->connect(td::network::Dns::Resolve("localhost"), port); - } - } - if (triedToCreate) - ImGui::Text("Failed to launch server"); - ImGui::EndPopup(); - } else { - triedToCreate = false; - } - - ImGui::End(); -} - -ImVec4 getImGuiTeamColor(td::game::TeamColor color) { - switch (color) { - case td::game::TeamColor::None: - break; - case td::game::TeamColor::Red: - return ImVec4(1, 0, 0, 1); - case td::game::TeamColor::Blue: - return ImVec4(0, 0, 1, 1); - } - return ImVec4(1, 1, 1, 1); -} - -void showPlayers() { - if (ImGui::TreeNode(std::string("Players (" + std::to_string(client->getGame().getPlayers().size()) + ")##player_list").c_str())) { - for (auto pair : client->getGame().getPlayers()) { - const td::game::Player& player = pair.second; - ImGui::PushStyleColor(ImGuiCol_Text, getImGuiTeamColor(player.getTeamColor())); - ImGui::Text("%s", player.getName().c_str()); - ImGui::PopStyleColor(); - } - ImGui::TreePop(); - } -} - -void showTeamSelection() { - if (client->getGame().getPlayer() == nullptr) - return; - td::game::TeamColor playerTeam = client->getGame().getPlayer()->getTeamColor(); - - if (ImGui::Button(std::string((playerTeam == td::game::TeamColor::Red ? "Leave" : "Join") + std::string(" Red Team")).c_str())) { - if (playerTeam == td::game::TeamColor::Red) - client->selectTeam(td::game::TeamColor::None); - else - client->selectTeam(td::game::TeamColor::Red); - } - ImGui::SameLine(); - if (ImGui::Button(std::string((playerTeam == td::game::TeamColor::Blue ? "Leave" : "Join") + std::string(" Blue Team")).c_str())) { - if (playerTeam == td::game::TeamColor::Blue) - client->selectTeam(td::game::TeamColor::None); - else - client->selectTeam(td::game::TeamColor::Blue); - } -} - -void showLobbyProgress() { - const int timePassed = LOBBY_WAITING_TIME - client->getGame().getLobbyTime(); - const float progress = (float)timePassed / (float)(LOBBY_WAITING_TIME); - if (progress > 0 && progress < 1) { - ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f), std::string(std::to_string(client->getGame().getLobbyTime() / 1000) + "s").c_str()); - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::Text("Time Remaining"); - } else { - ImGui::Text("Waiting for players ...\n"); - } -} - -void showTPS() { - ImGui::Text("Server TPS : %.1f", client->getConnexion().getServerTPS()); - ImGui::Text("Server Ping : %i", client->getConnexion().getServerPing()); -} - -void showStats() { - ImGui::Text("Gold : %i", client->getGame().getPlayer()->getGold()); -} - -void capValues(int* values, int& value) { - value = std::max(0, value); - value = std::min(12, value); - int total = 0; - for (int j = 0; j < 16; j++) { - total += values[j]; - } - if (total == 13) - value--; -} - -void renderSummonMenu() { - -} - -void renderGame() { - if (client->getGame().getGameState() == td::game::GameState::Lobby) { - ImGui::Begin("Lobby"); - - showTPS(); - showPlayers(); - showLobbyProgress(); - showTeamSelection(); - - ImGui::End(); - } - if (client->getGame().getGameState() == td::game::GameState::Game) { - ImGui::Begin("Game"); - - showTPS(); - showStats(); - showPlayers(); - guiManager.renderWidgets(); - - ImGui::End(); - } -} - void tick() { static std::uint64_t lastTime = td::utils::getTime(); std::uint64_t time = td::utils::getTime(); @@ -287,9 +98,9 @@ void render() { beginFrame(); client->render(); if (client->isConnected()) - renderGame(); + gameMenu->render(); else - renderMainMenu(); + mainMenu->render(); static bool demo_open = false; if (demo_open) ImGui::ShowDemoWindow(&demo_open);