From 83177729e93d90b087ced75168c428d626306178 Mon Sep 17 00:00:00 2001 From: mlangkabel Date: Mon, 3 Aug 2026 21:11:02 +0200 Subject: [PATCH] extract MainWindow::reloadConfig --- src/ui/MainWindow.cpp | 69 ++++++++++++++++++++----------------------- src/ui/MainWindow.h | 8 +++++ 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index 6df9ad0..896eb59 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -201,19 +201,9 @@ void MainWindow::handleEvent(std::shared_ptr /*e QAbstractButton* clicked = box.clickedButton(); if (clicked == restartBtn) { - std::shared_ptr newConfig; - try + std::optional newConfig = reloadConfig(); + if (!newConfig.has_value()) { - newConfig = std::make_shared( - ConfigLoader::loadFromDirectory(m_configDir)); - VisualsConfig newVisuals = VisualsLoader::load(m_configDir + "/visuals.toml"); - m_visuals = std::move(newVisuals); - m_dimOverlay->setDimColor(m_visuals.overlays.modalDim); - } - catch (const std::exception& e) - { - QMessageBox::critical(this, tr("Config Error"), - tr("Failed to reload config:\n%1").arg(e.what())); m_gameWorldView->setGameSpeed(prevSpeed); m_gameWorldView->resetFrameTimer(); return; @@ -221,7 +211,7 @@ void MainWindow::handleEvent(std::shared_ptr /*e // Restart is a command boundary; the view resets when the drain applies // it (see GameWorldView::onFrame). A fresh random seed starts a new run. std::shared_ptr command = std::make_shared(); - command->config = std::move(newConfig); + command->config = std::make_shared(std::move(*newConfig)); command->seed = std::random_device{}(); EventManager::getInstance()->sendEventImmediately( std::make_shared(command)); @@ -237,6 +227,27 @@ void MainWindow::handleEvent(std::shared_ptr /*e } } +std::optional MainWindow::reloadConfig() +{ + // Config is reloaded from disk on every restart (REQ-CFG-RELOAD); a malformed + // file must not leave the window half-updated, so the visuals are only applied + // once both files have parsed. + try + { + GameConfig newConfig = ConfigLoader::loadFromDirectory(m_configDir); + VisualsConfig newVisuals = VisualsLoader::load(m_configDir + "/visuals.toml"); + m_visuals = std::move(newVisuals); + m_dimOverlay->setDimColor(m_visuals.overlays.modalDim); + return newConfig; + } + catch (const std::exception& e) + { + QMessageBox::critical(this, tr("Config Error"), + tr("Failed to reload config:\n%1").arg(e.what())); + return std::nullopt; + } +} + void MainWindow::openShipLayoutDialog(BuildingId shipyardId, const std::string& schematicId, const ShipLayoutConfig& currentLayout) @@ -382,24 +393,14 @@ void MainWindow::handleEvent(std::shared_ptr /*event*/) if (box.clickedButton() == restartBtn) { - std::shared_ptr newConfig; - try + std::optional newConfig = reloadConfig(); + if (!newConfig.has_value()) { - newConfig = std::make_shared( - ConfigLoader::loadFromDirectory(m_configDir)); - VisualsConfig newVisuals = VisualsLoader::load(m_configDir + "/visuals.toml"); - m_visuals = std::move(newVisuals); - m_dimOverlay->setDimColor(m_visuals.overlays.modalDim); - } - catch (const std::exception& e) - { - QMessageBox::critical(this, tr("Config Error"), - tr("Failed to reload config:\n%1").arg(e.what())); return; } // Restart is a command boundary; the view resets when the drain applies it. std::shared_ptr command = std::make_shared(); - command->config = std::move(newConfig); + command->config = std::make_shared(std::move(*newConfig)); command->seed = std::random_device{}(); EventManager::getInstance()->sendEventImmediately( std::make_shared(command)); @@ -429,20 +430,14 @@ void MainWindow::handleEvent(std::shared_ptr /*event*/) if (box.clickedButton() == restartBtn) { - try + std::optional newConfig = reloadConfig(); + if (!newConfig.has_value()) { - GameConfig newConfig = ConfigLoader::loadFromDirectory(m_configDir); - VisualsConfig newVisuals = VisualsLoader::load(m_configDir + "/visuals.toml"); - m_visuals = std::move(newVisuals); - m_dimOverlay->setDimColor(m_visuals.overlays.modalDim); - m_sim->reset(std::move(newConfig)); - } - catch (const std::exception& e) - { - QMessageBox::critical(this, tr("Config Error"), - tr("Failed to reload config:\n%1").arg(e.what())); return; } + // Unlike the other two restart paths this one resets the simulation + // directly instead of enqueueing a ResetCommand; kept as-is. + m_sim->reset(std::move(*newConfig)); m_gameWorldView->resetForNewGame(); } else diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index d5ea17f..f61eda3 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -9,6 +10,7 @@ #include "BuildingId.h" #include "EscapeMenuRequestedEvent.h" #include "EventHandler.h" +#include "GameConfig.h" #include "GameOverEvent.h" #include "LayoutDialogRequestedEvent.h" #include "ModalDimOverlay.h" @@ -58,6 +60,12 @@ private: void handleEvent(std::shared_ptr event) override; void handleEvent(std::shared_ptr event) override; + // Reloads the game config and visuals.toml from disk (REQ-CFG-RELOAD), shared + // by every restart path. On success the reloaded visuals are applied to this + // window and the fresh GameConfig is returned; on failure a modal error dialog + // is shown and std::nullopt is returned, leaving the window state untouched. + std::optional reloadConfig(); + // Opens the shipyard layout configuration dialog for the given schematic and // current layout, applying the result via SetShipLayoutCommand (REQ-MOD-UI-DIALOG). void openShipLayoutDialog(BuildingId shipyardId,