reinici real (execv) des del service menu

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).
This commit is contained in:
2026-05-17 10:12:22 +02:00
parent 2c1673d2dd
commit 11eec8f222
4 changed files with 64 additions and 18 deletions
+43 -7
View File
@@ -3,7 +3,9 @@
#include <SDL3/SDL.h> // Para SDL_SetLogPriority, SDL_LogCategory, SDL_LogPriority, SDL_Quit #include <SDL3/SDL.h> // Para SDL_SetLogPriority, SDL_LogCategory, SDL_LogPriority, SDL_Quit
#include <cerrno> // Para errno
#include <cstdlib> // Para srand, exit, rand, EXIT_FAILURE #include <cstdlib> // Para srand, exit, rand, EXIT_FAILURE
#include <cstring> // Para std::strerror
#include <ctime> // Para time #include <ctime> // Para time
#include <fstream> // Para ifstream, ofstream #include <fstream> // Para ifstream, ofstream
#include <iostream> // Para basic_ostream, operator<<, cerr #include <iostream> // Para basic_ostream, operator<<, cerr
@@ -11,6 +13,12 @@
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
#include <string> // Para allocator, basic_string, char_traits, operator+, string, operator== #include <string> // Para allocator, basic_string, char_traits, operator+, string, operator==
#ifdef _WIN32
#include <process.h> // Per _execv
#else
#include <unistd.h> // Per execv
#endif
#include "core/audio/audio.hpp" // Para Audio #include "core/audio/audio.hpp" // Para Audio
#include "core/input/input.hpp" // Para Input #include "core/input/input.hpp" // Para Input
#include "core/locale/lang.hpp" // Para setLanguage #include "core/locale/lang.hpp" // Para setLanguage
@@ -71,7 +79,8 @@ namespace {
} // namespace } // namespace
// Constructor // Constructor
Director::Director() { Director::Director(int /*argc*/, char** argv)
: argv_(argv) {
Section::attract_mode = Section::AttractMode::TITLE_TO_DEMO; Section::attract_mode = Section::AttractMode::TITLE_TO_DEMO;
// Establece el nivel de prioridad de la categoría de registro // 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 // Allibera tots els singletons i SDL (compartit entre close() i relaunch())
void Director::close() { void Director::shutdownSubsystems() {
// Guarda las opciones actuales en el archivo de configuración // Guarda las opciones actuales en el archivo de configuración
Options::saveToFile(); Options::saveToFile();
@@ -228,15 +237,40 @@ void Director::close() {
Screen::destroy(); // Libera el sistema de pantalla y renderizado Screen::destroy(); // Libera el sistema de pantalla y renderizado
Asset::destroy(); // Libera el gestor de archivos Asset::destroy(); // Libera el gestor de archivos
std::cout << "\nBye!\n";
// Libera todos los recursos de SDL // Libera todos los recursos de SDL
SDL_Quit(); SDL_Quit();
}
// Cierra todo y libera recursos del sistema y de los singletons
void Director::close() {
shutdownSubsystems();
std::cout << "\nBye!\n";
// Apaga el sistema // Apaga el sistema
shutdownSystem(Section::options == Section::Options::SHUTDOWN); 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 // Carga los parametros
void Director::loadParams() { void Director::loadParams() {
// Carga los parametros para configurar el juego // 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 // Destruye la sección anterior y construye la nueva cuando Section::name cambia
void Director::handleSectionTransition() { 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) { 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(); reset();
} }
+10 -8
View File
@@ -2,13 +2,12 @@
#include <SDL3/SDL.h> // Para SDL_AppResult, SDL_Event #include <SDL3/SDL.h> // Para SDL_AppResult, SDL_Event
#include <memory> // Para unique_ptr #include <cstdint> // Para std::uint8_t
#include <string> // Para string #include <memory> // Para unique_ptr
#include <string> // Para string
#include "core/system/section.hpp" // Para Section::Name #include "core/system/section.hpp" // Para Section::Name
#include <cstdint> // Para std::uint8_t
namespace Lang { namespace Lang {
enum class Code : std::uint8_t; enum class Code : std::uint8_t;
} }
@@ -27,7 +26,7 @@ class Credits;
class Director { class Director {
public: public:
// --- Constructor y destructor --- // --- Constructor y destructor ---
Director(); Director(int argc, char** argv);
~Director(); ~Director();
// --- Callbacks para SDL_MAIN_USE_CALLBACKS --- // --- Callbacks para SDL_MAIN_USE_CALLBACKS ---
@@ -55,6 +54,7 @@ class Director {
// --- Variables internas --- // --- Variables internas ---
std::string executable_path_; // Ruta del ejecutable std::string executable_path_; // Ruta del ejecutable
std::string system_folder_; // Carpeta del sistema para almacenar datos 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) --- // --- Sección activa (una y sólo una viva en cada momento) ---
std::unique_ptr<Preload> preload_; std::unique_ptr<Preload> preload_;
@@ -71,9 +71,11 @@ class Director {
bool boot_loading_ = true; // True mientras Resource::loadStep está cargando incremental bool boot_loading_ = true; // True mientras Resource::loadStep está cargando incremental
// --- Inicialización y cierre del sistema --- // --- Inicialización y cierre del sistema ---
void init(); // Inicializa la aplicación (pre-boot) void init(); // Inicializa la aplicación (pre-boot)
static void finishBoot(); // Post-boot: inicializa lo que depende de recursos cargados static void finishBoot(); // Post-boot: inicializa lo que depende de recursos cargados
static void close(); // Cierra y libera recursos 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 --- // --- Configuración inicial ---
static void loadParams(); // Carga los parámetros del programa static void loadParams(); // Carga los parámetros del programa
+9 -1
View File
@@ -564,13 +564,21 @@ void ServiceMenu::addSettingsOptions() {
} }
void ServiceMenu::addSystemOptions() { 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<ActionOption>( options_.push_back(std::make_unique<ActionOption>(
Lang::getText("[SERVICE_MENU] RESET"), Lang::getText("[SERVICE_MENU] RESET"),
SettingsGroup::SYSTEM, SettingsGroup::SYSTEM,
[this]() -> void { [this]() -> void {
Section::name = Section::Name::RESET; Section::name = Section::Name::RESET;
toggle(); toggle();
})); },
RESET_HIDDEN));
options_.push_back(std::make_unique<ActionOption>( options_.push_back(std::make_unique<ActionOption>(
Lang::getText("[SERVICE_MENU] QUIT"), Lang::getText("[SERVICE_MENU] QUIT"),
+2 -2
View File
@@ -12,8 +12,8 @@ Actualizando a la versión "Arcade Edition" en 08/05/2024
#include "core/system/director.hpp" // Para Director #include "core/system/director.hpp" // Para Director
auto SDL_AppInit(void** appstate, int /*argc*/, char** /*argv*/) -> SDL_AppResult { auto SDL_AppInit(void** appstate, int argc, char** argv) -> SDL_AppResult {
*appstate = new Director(); *appstate = new Director(argc, argv);
return SDL_APP_CONTINUE; return SDL_APP_CONTINUE;
} }