diff --git a/CMakeLists.txt b/CMakeLists.txt index b6cc044..ed85500 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ set(ENTITY_SOURCES set(APP_SOURCES source/main.cpp source/core/system/director.cpp + source/core/system/relaunch.cpp source/core/audio/audio.cpp source/core/audio/audio_adapter.cpp source/core/audio/audio_effects.cpp diff --git a/source/core/system/relaunch.cpp b/source/core/system/relaunch.cpp new file mode 100644 index 0000000..a41221b --- /dev/null +++ b/source/core/system/relaunch.cpp @@ -0,0 +1,51 @@ +// relaunch.cpp - Implementació del reinici en calent + +#include "core/system/relaunch.hpp" + +#include +#include +#include +#include + +#ifdef _WIN32 +#include // _execv +#else +#include // execv +#endif + +namespace { + + // Estat global (process-scope). Aquesta TU és l'única que gestiona el + // reinici, així que els statics interns no s'escapen. + char** g_argv = nullptr; + bool g_requested = false; + +} // namespace + +namespace System::Relaunch { + + void setArgv(int /*argc*/, char** argv) { + g_argv = argv; + } + + void request() { + g_requested = true; + } + + void execIfRequested() { + if (!g_requested || g_argv == nullptr || g_argv[0] == nullptr) { + return; + } + std::cout << "[Relaunch] Reiniciant " << g_argv[0] << "...\n"; +#ifdef _WIN32 + _execv(g_argv[0], g_argv); +#else + execv(g_argv[0], g_argv); +#endif + // Si arribem aquí, execv ha fallat. Tots els subsistemes ja estan + // destruïts; sortim amb error i el shell rebrà el codi. + std::cerr << "[Relaunch] Ha fallat: " << std::strerror(errno) << '\n'; + std::exit(EXIT_FAILURE); + } + +} // namespace System::Relaunch diff --git a/source/core/system/relaunch.hpp b/source/core/system/relaunch.hpp new file mode 100644 index 0000000..982428c --- /dev/null +++ b/source/core/system/relaunch.hpp @@ -0,0 +1,28 @@ +// relaunch.hpp - Reinici en calent del procés (execv) +// +// Helper desacoblat perquè el menú de servei demani un reinici sense conèixer +// ni Director ni main.cpp. Patró d'ús: +// +// main() → Relaunch::setArgv(argc, argv) (a l'arrencada) +// ServiceMenu → Relaunch::request() (en activar "Reiniciar") +// main() → Relaunch::execIfRequested() (al final de SDL_AppQuit) +// +// L'execv() reemplaça el procés actual: si torna, ha fallat. Es crida després +// de destruir el Director per garantir que GPU/àudio/SDL ja són morts. + +#pragma once + +namespace System::Relaunch { + + // Emmagatzema l'argv original. Cal cridar-ho una vegada des de main. + void setArgv(int argc, char** argv); + + // Demana un reinici (no actua immediatament; només marca el flag). + void request(); + + // Si hi ha reinici demanat i tenim argv vàlid, fa execv. En cas d'èxit + // no torna. Si execv falla, registra l'error per stderr i surt amb + // EXIT_FAILURE (no podem reprendre — els subsistemes ja estan destruïts). + void execIfRequested(); + +} // namespace System::Relaunch diff --git a/source/game/ui/service_menu.cpp b/source/game/ui/service_menu.cpp index aa7cd56..54ad311 100644 --- a/source/game/ui/service_menu.cpp +++ b/source/game/ui/service_menu.cpp @@ -15,6 +15,7 @@ #include "core/rendering/screen.hpp" #include "core/rendering/text.hpp" #include "core/system/event_buffer.hpp" +#include "core/system/relaunch.hpp" #include "core/ui/ui_config.hpp" #include "game/gameplay_config.hpp" #include "game/options.hpp" @@ -1228,18 +1229,17 @@ auto ServiceMenu::buildSystem() -> Page { page.items.push_back(makeLabel( std::string("ver.") + Texts::VERSION + " (" + Version::GIT_HASH + ")")); - // Reiniciar el joc: tornem al LOGO amb `reset=true` perquè LogoScene - // ature música i sons abans de mostrar-se. Tanquem el menú a la - // mateixa acció — Director recollirà la transició al final del frame - // via `takePendingSceneRequest()` i reconstruirà l'escena. + // Reinici real del procés: marquem el flag i empenyem QUIT. SDL_AppQuit + // destruirà tots els subsistemes i llavors farà execv (al final, amb tot + // net) per substituir el binari per ell mateix. Si execv falla, el procés + // surt amb error. page.items.push_back(makeAction( "menu.items.restart", []() { - ServiceMenu::get().requestSceneTransition(ExitRequest{ - .next = SceneId::LOGO, - .params = LogoParams{.reset = true}, - }); - ServiceMenu::get().close(); + System::Relaunch::request(); + SDL_Event quit_event{}; + quit_event.type = SDL_EVENT_QUIT; + EventBuffer::events.push_back(quit_event); })); page.items.push_back(makeAction( diff --git a/source/main.cpp b/source/main.cpp index 6651884..ba6068a 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -7,11 +7,13 @@ #include "core/system/director.hpp" #include "core/system/event_buffer.hpp" +#include "core/system/relaunch.hpp" #include "utils/log.hpp" auto SDL_AppInit(void** appstate, int argc, char* argv[]) -> SDL_AppResult { - (void)argc; - (void)argv; + // Desem argv perquè el menú de servei pugui demanar un reinici en calent + // (execv) sense haver de conèixer ni Director ni main. + System::Relaunch::setArgv(argc, argv); // Logger primer de tot perquè l'arrencada del Director ja emet logs. Log::init(); @@ -45,6 +47,10 @@ void SDL_AppQuit(void* appstate, SDL_AppResult result) { { std::unique_ptr director(static_cast(appstate)); } + // Si el menú va demanar reinici, fem execv ara que tot està net. En èxit + // no torna (el procés és reemplaçat) i el "Bye!" no s'imprimeix — correcte, + // no és una sortida. + System::Relaunch::execIfRequested(); // Marcador de fi: ha de ser l'ÚLTIMA línia de log del programa. Log::raw(Log::Level::INFO, "Bye!"); }