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 <cerrno> // Para errno
#include <cstdlib> // Para srand, exit, rand, EXIT_FAILURE
#include <cstring> // Para std::strerror
#include <ctime> // Para time
#include <fstream> // Para ifstream, ofstream
#include <iostream> // Para basic_ostream, operator<<, cerr
@@ -11,6 +13,12 @@
#include <stdexcept> // Para runtime_error
#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/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();
}
+10 -8
View File
@@ -2,13 +2,12 @@
#include <SDL3/SDL.h> // Para SDL_AppResult, SDL_Event
#include <memory> // Para unique_ptr
#include <string> // Para string
#include <cstdint> // Para std::uint8_t
#include <memory> // Para unique_ptr
#include <string> // Para string
#include "core/system/section.hpp" // Para Section::Name
#include <cstdint> // 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> 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
+9 -1
View File
@@ -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<ActionOption>(
Lang::getText("[SERVICE_MENU] RESET"),
SettingsGroup::SYSTEM,
[this]() -> void {
Section::name = Section::Name::RESET;
toggle();
}));
},
RESET_HIDDEN));
options_.push_back(std::make_unique<ActionOption>(
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
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;
}