extract MainWindow::reloadConfig

This commit is contained in:
2026-08-03 21:11:02 +02:00
parent a8e933b7f2
commit 83177729e9
2 changed files with 40 additions and 37 deletions

View File

@@ -201,19 +201,9 @@ void MainWindow::handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> /*e
QAbstractButton* clicked = box.clickedButton(); QAbstractButton* clicked = box.clickedButton();
if (clicked == restartBtn) if (clicked == restartBtn)
{ {
std::shared_ptr<GameConfig> newConfig; std::optional<GameConfig> newConfig = reloadConfig();
try if (!newConfig.has_value())
{ {
newConfig = std::make_shared<GameConfig>(
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->setGameSpeed(prevSpeed);
m_gameWorldView->resetFrameTimer(); m_gameWorldView->resetFrameTimer();
return; return;
@@ -221,7 +211,7 @@ void MainWindow::handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> /*e
// Restart is a command boundary; the view resets when the drain applies // Restart is a command boundary; the view resets when the drain applies
// it (see GameWorldView::onFrame). A fresh random seed starts a new run. // it (see GameWorldView::onFrame). A fresh random seed starts a new run.
std::shared_ptr<ResetCommand> command = std::make_shared<ResetCommand>(); std::shared_ptr<ResetCommand> command = std::make_shared<ResetCommand>();
command->config = std::move(newConfig); command->config = std::make_shared<GameConfig>(std::move(*newConfig));
command->seed = std::random_device{}(); command->seed = std::random_device{}();
EventManager::getInstance()->sendEventImmediately( EventManager::getInstance()->sendEventImmediately(
std::make_shared<CommandRequestedEvent>(command)); std::make_shared<CommandRequestedEvent>(command));
@@ -237,6 +227,27 @@ void MainWindow::handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> /*e
} }
} }
std::optional<GameConfig> 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, void MainWindow::openShipLayoutDialog(BuildingId shipyardId,
const std::string& schematicId, const std::string& schematicId,
const ShipLayoutConfig& currentLayout) const ShipLayoutConfig& currentLayout)
@@ -382,24 +393,14 @@ void MainWindow::handleEvent(std::shared_ptr<const GameOverEvent> /*event*/)
if (box.clickedButton() == restartBtn) if (box.clickedButton() == restartBtn)
{ {
std::shared_ptr<GameConfig> newConfig; std::optional<GameConfig> newConfig = reloadConfig();
try if (!newConfig.has_value())
{ {
newConfig = std::make_shared<GameConfig>(
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; return;
} }
// Restart is a command boundary; the view resets when the drain applies it. // Restart is a command boundary; the view resets when the drain applies it.
std::shared_ptr<ResetCommand> command = std::make_shared<ResetCommand>(); std::shared_ptr<ResetCommand> command = std::make_shared<ResetCommand>();
command->config = std::move(newConfig); command->config = std::make_shared<GameConfig>(std::move(*newConfig));
command->seed = std::random_device{}(); command->seed = std::random_device{}();
EventManager::getInstance()->sendEventImmediately( EventManager::getInstance()->sendEventImmediately(
std::make_shared<CommandRequestedEvent>(command)); std::make_shared<CommandRequestedEvent>(command));
@@ -429,20 +430,14 @@ void MainWindow::handleEvent(std::shared_ptr<const WinEvent> /*event*/)
if (box.clickedButton() == restartBtn) if (box.clickedButton() == restartBtn)
{ {
try std::optional<GameConfig> 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; 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(); m_gameWorldView->resetForNewGame();
} }
else else

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -9,6 +10,7 @@
#include "BuildingId.h" #include "BuildingId.h"
#include "EscapeMenuRequestedEvent.h" #include "EscapeMenuRequestedEvent.h"
#include "EventHandler.h" #include "EventHandler.h"
#include "GameConfig.h"
#include "GameOverEvent.h" #include "GameOverEvent.h"
#include "LayoutDialogRequestedEvent.h" #include "LayoutDialogRequestedEvent.h"
#include "ModalDimOverlay.h" #include "ModalDimOverlay.h"
@@ -58,6 +60,12 @@ private:
void handleEvent(std::shared_ptr<const LayoutDialogRequestedEvent> event) override; void handleEvent(std::shared_ptr<const LayoutDialogRequestedEvent> event) override;
void handleEvent(std::shared_ptr<const RecipeSelectionRequestedEvent> event) override; void handleEvent(std::shared_ptr<const RecipeSelectionRequestedEvent> 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<GameConfig> reloadConfig();
// Opens the shipyard layout configuration dialog for the given schematic and // Opens the shipyard layout configuration dialog for the given schematic and
// current layout, applying the result via SetShipLayoutCommand (REQ-MOD-UI-DIALOG). // current layout, applying the result via SetShipLayoutCommand (REQ-MOD-UI-DIALOG).
void openShipLayoutDialog(BuildingId shipyardId, void openShipLayoutDialog(BuildingId shipyardId,