/* * TowerGui.cpp * * Created on: 5 nov. 2020 * Author: simon */ #include "render/gui/TowerGui.h" #include "imgui/imgui.h" #include "imgui/imgui_impl_opengl3.h" #include "imgui/imgui_impl_sdl.h" #include #include #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 #include namespace TowerGui { static SDL_Window* window; static SDL_GLContext gl_context; static std::unique_ptr client; static std::thread* serverThread; static td::render::Renderer* renderer; bool serverShouldStop = false; void init(SDL_Window* sdl_window, SDL_GLContext sdlContext, td::render::Renderer* render) { window = sdl_window; gl_context = sdlContext; IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGui::StyleColorsDark(); ImGui_ImplSDL2_InitForOpenGL(sdl_window, gl_context); const char* glslVersion = "#version 130"; ImGui_ImplOpenGL3_Init(glslVersion); ImFontConfig c; c.SizePixels = 25; ImGui::GetIO().Fonts->AddFontDefault(&c); renderer = render; client = std::make_unique(render); } void beginFrame() { ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplSDL2_NewFrame(); ImGui::NewFrame(); } void endFrame() { ImGui::EndFrame(); ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } void renderFPSCounter() { ImGui::Begin("FPS Counter"); ImGui::Text("FPS : %i", (int)ImGui::GetIO().Framerate); static bool vsync = true; if (ImGui::Checkbox("V-Sync", &vsync)) { SDL_GL_SetSwapInterval(vsync); } static bool isometric = true; if (ImGui::Checkbox("Vue Isometrique ?", &isometric)) { renderer->setIsometricView(isometric); } 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(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(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() { static bool menu_open = true; if (menu_open) { ImGui::Begin("Summon", &menu_open); static int width = 100; static int values[16]{ 0 }; ImTextureID my_tex_id = ImGui::GetIO().Fonts->TexID; for (int i = 0; i < 8; i++) { ImGui::SameLine(); ImGui::PushID(i); ImGui::Image(my_tex_id, ImVec2(100, 100)); ImGui::PopID(); } ImGui::Separator(); ImGui::PushItemWidth(width); for (int i = 0; i < 8; i++) { ImGui::SameLine(); ImGui::PushID(i); if (ImGui::InputInt("", values + i, 1, 10)) { capValues(values, values[i]); } ImGui::PopID(); } ImGui::PopItemWidth(); ImGui::Separator(); for (int i = 0; i < 8; i++) { ImGui::SameLine(); ImGui::PushID(i); ImGui::Image(my_tex_id, ImVec2(100, 100)); ImGui::PopID(); } ImGui::Separator(); ImGui::PushItemWidth(width); for (int i = 8; i < 16; i++) { ImGui::SameLine(); ImGui::PushID(i); if (ImGui::InputInt("", values + i, 1, 10)) { capValues(values, values[i]); } ImGui::PopID(); } ImGui::PopItemWidth(); if (ImGui::Button("Send")) { std::cout << "Sending Troops ...\n"; } ImGui::End(); } } 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(); renderSummonMenu(); ImGui::End(); } } void tick() { static std::uint64_t lastTime = td::utils::getTime(); std::uint64_t time = td::utils::getTime(); std::uint64_t delta = time - lastTime; client->tick(delta); lastTime = td::utils::getTime(); } void render() { tick(); beginFrame(); client->render(); if (client->isConnected()) renderGame(); else renderMainMenu(); static bool demo_open = false; if (demo_open) ImGui::ShowDemoWindow(&demo_open); renderFPSCounter(); endFrame(); } void destroy() { client->closeConnection(); client.reset(); serverShouldStop = true; if (serverThread != nullptr) { serverThread->join(); delete serverThread; } ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); } }