From 41ce3fece59f7444ac437d50ec3c8aed769675dc Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Wed, 20 May 2026 19:40:52 +0200 Subject: [PATCH] refactor(#28): Director rep EngineConfig + ConfigPersistence, main orquestra MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pas 5/N del hallazgo #28. Director deixa d'incloure game/options.hpp i les seves crides a Options::*. El seu ctor accepta ara: - Config::EngineConfig& cfg → la struct runtime (window, console, ...). - Config::ConfigPersistence → 4 lambdes (init/set_path/load/save) que delegen la persistència a la capa concreta (game/Options::*). Cap més referència a Options:: ni a "game/..." dins del Director: - cfg_->* substitueix tot Options::* (window, console, player1/2, rendering, engine_config). - persistence_.{init,save,load,set_path} substitueix les funcions d'I/O de YAML. run() i checkProgramArguments deixen de ser estàtics (necessiten accés a cfg_ i persistence_). Això també desfà el smell del hallazgo #37 (Director::run estàtic que llegia estat d'instància). main.cpp queda com a orquestrador: construeix la struct ConfigPersistence amb lambdes que enllacen amb Options::* i la injecta al Director. Afegit: Config::ConfigPersistence a engine_config.hpp. Co-Authored-By: Claude Opus 4.7 (1M context) --- source/core/config/engine_config.hpp | 11 ++++++ source/core/system/director.cpp | 50 ++++++++++++------------ source/core/system/director.hpp | 58 +++++++++++++++------------- source/main.cpp | 25 +++++++++--- 4 files changed, 89 insertions(+), 55 deletions(-) diff --git a/source/core/config/engine_config.hpp b/source/core/config/engine_config.hpp index 47fd099..1d0b9bb 100644 --- a/source/core/config/engine_config.hpp +++ b/source/core/config/engine_config.hpp @@ -12,6 +12,7 @@ #include +#include #include namespace Config { @@ -58,4 +59,14 @@ namespace Config { bool console{false}; }; + // Capa de persistència delegada cap a l'EngineConfig. Permet al Director + // orquestrar init/load/save sense conèixer cap esquema concret (YAML, + // SQLite, ...) ni la capa que el conté (`game/options.cpp`). + struct ConfigPersistence { + std::function init_defaults; // Restaura valors per defecte + std::function set_path; // Indica on guardar + std::function load; // Llegeix path → EngineConfig + std::function save; // Escriu EngineConfig → path + }; + } // namespace Config diff --git a/source/core/system/director.cpp b/source/core/system/director.cpp index 29d1a18..2416d85 100644 --- a/source/core/system/director.cpp +++ b/source/core/system/director.cpp @@ -19,7 +19,6 @@ #include "core/resources/resource_loader.hpp" #include "core/utils/path_utils.hpp" #include "debug_overlay.hpp" -#include "game/options.hpp" #include "game/scenes/game_scene.hpp" #include "game/scenes/logo_scene.hpp" #include "game/scenes/title_scene.hpp" @@ -38,11 +37,15 @@ using SceneManager::SceneContext; using SceneType = SceneContext::SceneType; // Constructor -Director::Director(std::vector const& args) { +Director::Director(std::vector const& args, + Config::EngineConfig& cfg, + Config::ConfigPersistence persistence) + : cfg_(&cfg), + persistence_(std::move(persistence)) { std::cout << "Orni Attack - Inici\n"; // Inicialitzar opciones con valors per defecte - Options::init(); + persistence_.init_defaults(); // Comprovar arguments del programa executable_path_ = checkProgramArguments(args); @@ -90,22 +93,22 @@ Director::Director(std::vector const& args) { createSystemFolder(std::string("jailgames/") + Project::NAME); // Establir ruta del file de configuración - Options::setConfigFile(system_folder_ + "/config.yaml"); + persistence_.set_path(system_folder_ + "/config.yaml"); // Carregar o crear configuración - Options::loadFromFile(); + persistence_.load(); // Inicialitzar sistema de input Input::init("data/gamecontrollerdb.txt"); // Aplicar configuración de controls dels jugadors - Input::get()->applyPlayer1Bindings(Options::player1); - Input::get()->applyPlayer2Bindings(Options::player2); + Input::get()->applyPlayer1Bindings(cfg_->player1); + Input::get()->applyPlayer2Bindings(cfg_->player2); - if (Options::console) { + if (cfg_->console) { std::cout << "Configuración carregada\n"; - std::cout << " Finestra: " << Options::window.width << "×" - << Options::window.height << '\n'; + std::cout << " Finestra: " << cfg_->window.width << "×" + << cfg_->window.height << '\n'; std::cout << " Input: " << Input::get()->getNumGamepads() << " gamepad(s) detectat(s)\n"; } @@ -115,7 +118,7 @@ Director::Director(std::vector const& args) { Director::~Director() { // Guardar opciones - Options::saveToFile(); + persistence_.save(); // Cleanup input Input::destroy(); @@ -136,11 +139,11 @@ auto Director::checkProgramArguments(std::vector const& args) const std::string& argument = args[i]; if (argument == "--console") { - Options::console = true; + cfg_->console = true; std::cout << "Mode consola activat\n"; } else if (argument == "--reset-config") { - Options::init(); - Options::saveToFile(); + persistence_.init_defaults(); + persistence_.save(); std::cout << "Configuración restablida als valors per defecte\n"; } } @@ -207,7 +210,7 @@ void Director::createSystemFolder(const std::string& folder) { } } - if (Options::console) { + if (cfg_->console) { std::cout << "Carpeta del sistema: " << system_folder_ << '\n'; } } @@ -216,18 +219,17 @@ void Director::createSystemFolder(const std::string& folder) { auto Director::run() -> int { // Calculate initial size from saved zoom_factor int initial_width = static_cast(std::round( - Defaults::Window::WIDTH * Options::window.zoom_factor)); + Defaults::Window::WIDTH * cfg_->window.zoom_factor)); int initial_height = static_cast(std::round( - Defaults::Window::HEIGHT * Options::window.zoom_factor)); + Defaults::Window::HEIGHT * cfg_->window.zoom_factor)); - // Crear gestor SDL con configuración de Options. - // Inyectamos la engine_config + un callback per persistir-la quan - // toggleVSync (F4) muti vsync, sense que sdl_manager conegui Options. - SDLManager sdl(initial_width, initial_height, Options::window.fullscreen, Options::engine_config, [] { Options::saveToFile(); }); + // Crear gestor SDL amb la engine_config + callback de persistència + // per a quan toggleVSync (F4) muti vsync. Mantenim sdl_manager agnòstic. + SDLManager sdl(initial_width, initial_height, cfg_->window.fullscreen, *cfg_, [this] { persistence_.save(); }); // CRÍTIC: Forçar ocultació del cursor DESPRÉS de toda la inicialización SDL // Això evita que SDL mostre el cursor automàticament durante la creació de la finestra - if (!Options::window.fullscreen) { + if (!cfg_->window.fullscreen) { Mouse::forceHide(); } @@ -246,7 +248,7 @@ auto Director::run() -> int { // Precachear música para evitar lag al empezar AudioResource::getMusic("title.ogg"); AudioResource::getMusic("game.ogg"); - if (Options::console) { + if (cfg_->console) { std::cout << "Música precacheada\n"; } @@ -260,7 +262,7 @@ auto Director::run() -> int { // Overlay de debug (FPS + VSync). Vive en el Director porque es global // a todas las escenas. Toggle con F11 (visible por defecto en _DEBUG). - System::DebugOverlay debug_overlay(sdl.getRenderer(), Options::rendering); + System::DebugOverlay debug_overlay(sdl.getRenderer(), cfg_->rendering); // Bucle principal: construir escena → frame loop → destruir → siguiente. while (context.nextScene() != SceneType::EXIT) { diff --git a/source/core/system/director.hpp b/source/core/system/director.hpp index d4d16d7..c6ce16e 100644 --- a/source/core/system/director.hpp +++ b/source/core/system/director.hpp @@ -4,41 +4,47 @@ #include #include +#include "core/config/engine_config.hpp" #include "scene_context.hpp" class Scene; class SDLManager; -namespace System { class DebugOverlay; } +namespace System { + class DebugOverlay; +} class Director { - public: - explicit Director(std::vector const& args); - ~Director(); + public: + // `cfg` ha de viure tant com el Director (típicament owned per main). + // `persistence` encapsula init/load/save delegats a la capa concreta + // (game/Options::*). + Director(std::vector const& args, + Config::EngineConfig& cfg, + Config::ConfigPersistence persistence); + ~Director(); - // Main game loop. Estático: los miembros del Director (executable_path_, - // system_folder_) se establecen en el ctor y no se vuelven a leer aquí; - // el bucle solo orquesta sistemas globales (SDLManager, Options, Audio). - static auto run() -> int; + // Bucle principal del juego. + auto run() -> int; - private: - std::string executable_path_; - std::string system_folder_; + private: + std::string executable_path_; + std::string system_folder_; + Config::EngineConfig* cfg_; + Config::ConfigPersistence persistence_; - static auto checkProgramArguments(std::vector const& args) - -> std::string; - void createSystemFolder(const std::string& folder); + auto checkProgramArguments(std::vector const& args) + -> std::string; + void createSystemFolder(const std::string& folder); - // Construye la escena correspondiente al tipo solicitado. Retorna - // nullptr para EXIT u otros valores no constructibles. - static auto buildScene(SceneManager::SceneContext::SceneType type, - SDLManager& sdl, - SceneManager::SceneContext& context) - -> std::unique_ptr; + // Construye la escena correspondiente al tipo solicitado. Retorna + // nullptr para EXIT u otros valores no constructibles. + static auto buildScene(SceneManager::SceneContext::SceneType type, + SDLManager& sdl, + SceneManager::SceneContext& context) + -> std::unique_ptr; - // Ejecuta el bucle de frames de UNA escena hasta que scene.isFinished() - // sea true. Maneja delta_time, eventos (globales + escena), update y draw. - // El debug_overlay es global a todas las escenas; el Director lo posee. - static void runFrameLoop(Scene& scene, SDLManager& sdl, - SceneManager::SceneContext& context, - System::DebugOverlay& debug_overlay); + // Ejecuta el bucle de frames de UNA escena hasta que scene.isFinished() + // sea true. Maneja delta_time, eventos (globales + escena), update y draw. + // El debug_overlay es global a todas las escenas; el Director lo posee. + static void runFrameLoop(Scene& scene, SDLManager& sdl, SceneManager::SceneContext& context, System::DebugOverlay& debug_overlay); }; diff --git a/source/main.cpp b/source/main.cpp index 831bc43..68c7663 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,18 +1,33 @@ -// main.cpp - Vec2 de entrada del juego Asteroides +// main.cpp - Punt d'entrada de l'aplicació // © 2026 JailDesigner +// +// Aquí orquestrem la capa de persistència (YAML via game/Options::*) i +// injectem el resultat al Director. El Director queda independent de +// game/options.hpp i pot operar només amb Config::EngineConfig. #include #include +#include "core/config/engine_config.hpp" #include "core/system/director.hpp" +#include "game/options.hpp" auto main(int argc, char* argv[]) -> int { // Convertir arguments a std::vector std::vector args(argv, argv + argc); - // Crear director (inicialitza sistema, opciones, configuración) - Director director(args); + // Capa de persistència delegada: lambdes prim que enllacen el contracte + // de Config::ConfigPersistence amb la implementació YAML de Options::*. + const Config::ConfigPersistence PERSISTENCE{ + .init_defaults = [] { Options::init(); }, + .set_path = [](const std::string& path) { Options::setConfigFile(path); }, + .load = [] { return Options::loadFromFile(); }, + .save = [] { return Options::saveToFile(); }, + }; - // Executar bucle principal del juego - return Director::run(); + // El Director rep la struct d'engine_config + la capa de persistència. + // No coneix Options::* directament. + Director director(args, Options::engine_config, PERSISTENCE); + + return director.run(); }