From 11eec8f2228ac04849407ae4d0b9ceaf875d80e6 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sun, 17 May 2026 10:12:22 +0200 Subject: [PATCH] reinici real (execv) des del service menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El Reiniciar fins ara recarregava recursos però no rellegia el preset ni recreava la finestra (idioma/dificultat/preset es quedaven pendents fins al pròxim arrencada manual). Ara Director rep argv al constructor i, quan Section::name passa a RESET, fa execv del propi binari (_execv a Windows). El procés es reemplaça → init complet amb tots els canvis aplicats. Refactor: extret shutdownSubsystems() de close() i compartit amb relaunch(). Si execv falla els subsistemes ja s'han destruït, no podem tornar al bucle: exit amb error. A Emscripten s'amaga l'opció Reiniciar al service menu (execv no existeix; el cheat code per teclat encara cau al reset clàssic com fallback). --- source/core/system/director.cpp | 50 ++++++++++++++++++++++++++++----- source/core/system/director.hpp | 18 ++++++------ source/game/ui/service_menu.cpp | 10 ++++++- source/main.cpp | 4 +-- 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index c7e2ee4..feaaead 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -3,7 +3,9 @@ #include // Para SDL_SetLogPriority, SDL_LogCategory, SDL_LogPriority, SDL_Quit +#include // Para errno #include // Para srand, exit, rand, EXIT_FAILURE +#include // Para std::strerror #include // Para time #include // Para ifstream, ofstream #include // Para basic_ostream, operator<<, cerr @@ -11,6 +13,12 @@ #include // Para runtime_error #include // Para allocator, basic_string, char_traits, operator+, string, operator== +#ifdef _WIN32 +#include // Per _execv +#else +#include // Per execv +#endif + #include "core/audio/audio.hpp" // Para Audio #include "core/input/input.hpp" // Para Input #include "core/locale/lang.hpp" // Para setLanguage @@ -71,7 +79,8 @@ namespace { } // namespace // Constructor -Director::Director() { +Director::Director(int /*argc*/, char** argv) + : argv_(argv) { Section::attract_mode = Section::AttractMode::TITLE_TO_DEMO; // Establece el nivel de prioridad de la categoría de registro @@ -214,8 +223,8 @@ void Director::finishBoot() { } } -// Cierra todo y libera recursos del sistema y de los singletons -void Director::close() { +// Allibera tots els singletons i SDL (compartit entre close() i relaunch()) +void Director::shutdownSubsystems() { // Guarda las opciones actuales en el archivo de configuración Options::saveToFile(); @@ -228,15 +237,40 @@ void Director::close() { Screen::destroy(); // Libera el sistema de pantalla y renderizado Asset::destroy(); // Libera el gestor de archivos - std::cout << "\nBye!\n"; - // Libera todos los recursos de SDL SDL_Quit(); +} +// Cierra todo y libera recursos del sistema y de los singletons +void Director::close() { + shutdownSubsystems(); + std::cout << "\nBye!\n"; // Apaga el sistema shutdownSystem(Section::options == Section::Options::SHUTDOWN); } +// Reemplaça el procés actual per ell mateix (reinici en calent). En cas d'èxit no torna. +// Si no es pot reiniciar (Emscripten, argv invàlid), retorna i el caller fa el reset clàssic. +void Director::relaunch() const { +#ifdef __EMSCRIPTEN__ + // Al navegador el reinici real seria location.reload(); aquí caiem al reset intern. + return; +#else + if (argv_ == nullptr || argv_[0] == nullptr) { return; } + std::cout << "Relaunching " << argv_[0] << "...\n"; + shutdownSubsystems(); +#ifdef _WIN32 + _execv(argv_[0], argv_); +#else + execv(argv_[0], argv_); +#endif + // Si arribem aquí, execv ha fallat. Tots els subsistemes ja estan destruïts: no + // podem reprendre el bucle. Sortim amb error. + std::cerr << "Relaunch failed: " << std::strerror(errno) << "\n"; + std::exit(EXIT_FAILURE); +#endif +} + // Carga los parametros void Director::loadParams() { // Carga los parametros para configurar el juego @@ -354,9 +388,11 @@ void Director::resetActiveSection() { // Destruye la sección anterior y construye la nueva cuando Section::name cambia void Director::handleSectionTransition() { - // RESET: recarga recursos y vuelve a LOGO (el propio reset() cambia Section::name) + // RESET: intenta reinici real via execv; si no es pot (Emscripten o argv invàlid), + // cau al reset intern (recarrega recursos i torna a LOGO, sense recrear Screen/Params). if (Section::name == Section::Name::RESET) { - resetActiveSection(); // libera recursos actuales antes del reload + relaunch(); // En èxit no torna; el binari es reemplaça + resetActiveSection(); // Fallback: libera recursos actuales antes del reload reset(); } diff --git a/source/core/system/director.hpp b/source/core/system/director.hpp index 3f54159..80f2994 100644 --- a/source/core/system/director.hpp +++ b/source/core/system/director.hpp @@ -2,13 +2,12 @@ #include // Para SDL_AppResult, SDL_Event -#include // Para unique_ptr -#include // Para string +#include // Para std::uint8_t +#include // Para unique_ptr +#include // Para string #include "core/system/section.hpp" // Para Section::Name -#include // Para std::uint8_t - namespace Lang { enum class Code : std::uint8_t; } @@ -27,7 +26,7 @@ class Credits; class Director { public: // --- Constructor y destructor --- - Director(); + Director(int argc, char** argv); ~Director(); // --- Callbacks para SDL_MAIN_USE_CALLBACKS --- @@ -55,6 +54,7 @@ class Director { // --- Variables internas --- std::string executable_path_; // Ruta del ejecutable std::string system_folder_; // Carpeta del sistema para almacenar datos + char** argv_ = nullptr; // argv original; usat per relaunch() (execv) // --- Sección activa (una y sólo una viva en cada momento) --- std::unique_ptr preload_; @@ -71,9 +71,11 @@ class Director { bool boot_loading_ = true; // True mientras Resource::loadStep está cargando incremental // --- Inicialización y cierre del sistema --- - void init(); // Inicializa la aplicación (pre-boot) - static void finishBoot(); // Post-boot: inicializa lo que depende de recursos cargados - static void close(); // Cierra y libera recursos + void init(); // Inicializa la aplicación (pre-boot) + static void finishBoot(); // Post-boot: inicializa lo que depende de recursos cargados + static void shutdownSubsystems(); // Allibera singletons i SDL (sense apagar el sistema) + static void close(); // Cierra y libera recursos + void relaunch() const; // Reemplaça el procés via execv (fallback silenciós si no es pot) // --- Configuración inicial --- static void loadParams(); // Carga los parámetros del programa diff --git a/source/game/ui/service_menu.cpp b/source/game/ui/service_menu.cpp index 6a0fe1a..06d2520 100644 --- a/source/game/ui/service_menu.cpp +++ b/source/game/ui/service_menu.cpp @@ -564,13 +564,21 @@ void ServiceMenu::addSettingsOptions() { } void ServiceMenu::addSystemOptions() { + // Al navegador no podem reiniciar el procés (execv no existeix), així que amaguem + // l'opció en compte de mostrar un fals reset que no recarrega params/finestra. +#ifdef __EMSCRIPTEN__ + constexpr bool RESET_HIDDEN = true; +#else + constexpr bool RESET_HIDDEN = false; +#endif options_.push_back(std::make_unique( Lang::getText("[SERVICE_MENU] RESET"), SettingsGroup::SYSTEM, [this]() -> void { Section::name = Section::Name::RESET; toggle(); - })); + }, + RESET_HIDDEN)); options_.push_back(std::make_unique( Lang::getText("[SERVICE_MENU] QUIT"), diff --git a/source/main.cpp b/source/main.cpp index 4f7ec68..c06b1a7 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -12,8 +12,8 @@ Actualizando a la versión "Arcade Edition" en 08/05/2024 #include "core/system/director.hpp" // Para Director -auto SDL_AppInit(void** appstate, int /*argc*/, char** /*argv*/) -> SDL_AppResult { - *appstate = new Director(); +auto SDL_AppInit(void** appstate, int argc, char** argv) -> SDL_AppResult { + *appstate = new Director(argc, argv); return SDL_APP_CONTINUE; }