implement load config on game restart
This commit is contained in:
@@ -9,7 +9,6 @@
|
|||||||
#include "LogManager.h"
|
#include "LogManager.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "Simulation.h"
|
#include "Simulation.h"
|
||||||
#include "VisualsLoader.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@@ -33,10 +32,9 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameConfig config = ConfigLoader::loadFromDirectory(DOTA_FACTORY_CONFIG_DIR);
|
GameConfig config = ConfigLoader::loadFromDirectory(DOTA_FACTORY_CONFIG_DIR);
|
||||||
VisualsConfig visuals = VisualsLoader::load(std::string(DOTA_FACTORY_CONFIG_DIR) + "/visuals.toml");
|
std::unique_ptr<Simulation> sim = std::make_unique<Simulation>(std::move(config));
|
||||||
std::unique_ptr<Simulation> sim = std::make_unique<Simulation>(config);
|
|
||||||
|
|
||||||
MainWindow window(sim.get(), &config, &visuals);
|
MainWindow window(sim.get(), std::string(DOTA_FACTORY_CONFIG_DIR));
|
||||||
window.show();
|
window.show();
|
||||||
|
|
||||||
const int ret = application.exec();
|
const int ret = application.exec();
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
#include "ShipsConfig.h"
|
#include "ShipsConfig.h"
|
||||||
#include "StationsConfig.h"
|
#include "StationsConfig.h"
|
||||||
|
|
||||||
// Aggregate of all five simulation config files, loaded once at startup and
|
// Aggregate of all five simulation config files. Loaded at startup and reloaded
|
||||||
// immutable for the rest of the game. See architecture.md "Config Loading".
|
// from disk on each game restart (REQ-CFG-RELOAD). See architecture.md "Config Loading".
|
||||||
struct GameConfig
|
struct GameConfig
|
||||||
{
|
{
|
||||||
WorldConfig world;
|
WorldConfig world;
|
||||||
|
|||||||
@@ -9,23 +9,23 @@
|
|||||||
#include "SurfaceMask.h"
|
#include "SurfaceMask.h"
|
||||||
#include "WaveSystem.h"
|
#include "WaveSystem.h"
|
||||||
|
|
||||||
Simulation::Simulation(const GameConfig& config, unsigned int seed)
|
Simulation::Simulation(GameConfig config, unsigned int seed)
|
||||||
: m_config(config)
|
: m_config(std::move(config))
|
||||||
, m_rng(seed)
|
, m_rng(seed)
|
||||||
, m_currentTick(0)
|
, m_currentTick(0)
|
||||||
, m_nextId(1)
|
, m_nextId(1)
|
||||||
, m_buildingBlocksStock(config.world.startingBuildingBlocks)
|
, m_buildingBlocksStock(m_config.world.startingBuildingBlocks)
|
||||||
, m_gameOver(false)
|
, m_gameOver(false)
|
||||||
, m_hqId(kInvalidEntityId)
|
, m_hqId(kInvalidEntityId)
|
||||||
, m_playerStation1Id(kInvalidEntityId)
|
, m_playerStation1Id(kInvalidEntityId)
|
||||||
, m_playerStation2Id(kInvalidEntityId)
|
, m_playerStation2Id(kInvalidEntityId)
|
||||||
, m_beltSystem(config.world.beltSpeedTilesPerSecond)
|
, m_beltSystem(m_config.world.beltSpeedTilesPerSecond)
|
||||||
{
|
{
|
||||||
m_currentEnemyStationIds[0] = kInvalidEntityId;
|
m_currentEnemyStationIds[0] = kInvalidEntityId;
|
||||||
m_currentEnemyStationIds[1] = kInvalidEntityId;
|
m_currentEnemyStationIds[1] = kInvalidEntityId;
|
||||||
|
|
||||||
m_buildingSystem = std::make_unique<BuildingSystem>(
|
m_buildingSystem = std::make_unique<BuildingSystem>(
|
||||||
config,
|
m_config,
|
||||||
m_beltSystem,
|
m_beltSystem,
|
||||||
[this]() { return allocateId(); },
|
[this]() { return allocateId(); },
|
||||||
[this](int amount) { m_buildingBlocksStock += amount; },
|
[this](int amount) { m_buildingBlocksStock += amount; },
|
||||||
@@ -39,13 +39,13 @@ Simulation::Simulation(const GameConfig& config, unsigned int seed)
|
|||||||
m_shipSystem->spawn(id, it->second.level, pos, /*isEnemy=*/false);
|
m_shipSystem->spawn(id, it->second.level, pos, /*isEnemy=*/false);
|
||||||
},
|
},
|
||||||
m_rng);
|
m_rng);
|
||||||
m_shipSystem = std::make_unique<ShipSystem>(config, [this]() { return allocateId(); });
|
m_shipSystem = std::make_unique<ShipSystem>(m_config, [this]() { return allocateId(); });
|
||||||
m_scrapSystem = std::make_unique<ScrapSystem>([this]() { return allocateId(); });
|
m_scrapSystem = std::make_unique<ScrapSystem>([this]() { return allocateId(); });
|
||||||
m_waveSystem = std::make_unique<WaveSystem>(config, m_rng);
|
m_waveSystem = std::make_unique<WaveSystem>(m_config, m_rng);
|
||||||
m_combatSystem = std::make_unique<CombatSystem>(config);
|
m_combatSystem = std::make_unique<CombatSystem>(m_config);
|
||||||
|
|
||||||
// Initialize blueprint unlock state.
|
// Initialize blueprint unlock state.
|
||||||
for (const ShipDef& def : config.ships.ships)
|
for (const ShipDef& def : m_config.ships.ships)
|
||||||
{
|
{
|
||||||
BlueprintState state;
|
BlueprintState state;
|
||||||
state.unlocked = def.availableFromStart;
|
state.unlocked = def.availableFromStart;
|
||||||
@@ -58,6 +58,17 @@ Simulation::Simulation(const GameConfig& config, unsigned int seed)
|
|||||||
|
|
||||||
Simulation::~Simulation() = default;
|
Simulation::~Simulation() = default;
|
||||||
|
|
||||||
|
const GameConfig& Simulation::config() const
|
||||||
|
{
|
||||||
|
return m_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Simulation::reset(GameConfig newConfig, unsigned int seed)
|
||||||
|
{
|
||||||
|
m_config = std::move(newConfig);
|
||||||
|
reset(seed);
|
||||||
|
}
|
||||||
|
|
||||||
void Simulation::reset(unsigned int seed)
|
void Simulation::reset(unsigned int seed)
|
||||||
{
|
{
|
||||||
m_rng.seed(seed);
|
m_rng.seed(seed);
|
||||||
|
|||||||
@@ -26,12 +26,17 @@ class WaveSystem;
|
|||||||
class Simulation
|
class Simulation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Simulation(const GameConfig& config, unsigned int seed = 0);
|
explicit Simulation(GameConfig config, unsigned int seed = 0);
|
||||||
~Simulation();
|
~Simulation();
|
||||||
|
|
||||||
|
const GameConfig& config() const;
|
||||||
|
|
||||||
// Reinitializes all simulation state as if constructed fresh.
|
// Reinitializes all simulation state as if constructed fresh.
|
||||||
void reset(unsigned int seed = 0);
|
void reset(unsigned int seed = 0);
|
||||||
|
|
||||||
|
// Reloads config then reinitializes all simulation state.
|
||||||
|
void reset(GameConfig newConfig, unsigned int seed = 0);
|
||||||
|
|
||||||
// Advances the simulation by one tick. Tick order per architecture.md §Tick Order.
|
// Advances the simulation by one tick. Tick order per architecture.md §Tick Order.
|
||||||
void tick();
|
void tick();
|
||||||
|
|
||||||
@@ -83,7 +88,7 @@ private:
|
|||||||
// Award a random blueprint drop (REQ-DEF-BLUEPRINT-DROP) and emit the event.
|
// Award a random blueprint drop (REQ-DEF-BLUEPRINT-DROP) and emit the event.
|
||||||
void awardBlueprintDrop();
|
void awardBlueprintDrop();
|
||||||
|
|
||||||
const GameConfig& m_config;
|
GameConfig m_config;
|
||||||
std::mt19937 m_rng;
|
std::mt19937 m_rng;
|
||||||
|
|
||||||
Tick m_currentTick;
|
Tick m_currentTick;
|
||||||
|
|||||||
@@ -8,15 +8,18 @@
|
|||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "BuildButtonGrid.h"
|
#include "BuildButtonGrid.h"
|
||||||
|
#include "ConfigLoader.h"
|
||||||
#include "GameWorldView.h"
|
#include "GameWorldView.h"
|
||||||
#include "HeaderBar.h"
|
#include "HeaderBar.h"
|
||||||
#include "SelectedBuildingPanel.h"
|
#include "SelectedBuildingPanel.h"
|
||||||
#include "Simulation.h"
|
#include "Simulation.h"
|
||||||
#include "Tick.h"
|
#include "Tick.h"
|
||||||
|
#include "VisualsLoader.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(Simulation* sim, const GameConfig* config,
|
MainWindow::MainWindow(Simulation* sim, const std::string& configDir, QWidget* parent)
|
||||||
const VisualsConfig* visuals, QWidget* parent)
|
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
|
, m_configDir(configDir)
|
||||||
|
, m_visuals(VisualsLoader::load(configDir + "/visuals.toml"))
|
||||||
, m_sim(sim)
|
, m_sim(sim)
|
||||||
{
|
{
|
||||||
setWindowTitle("Dota Factory");
|
setWindowTitle("Dota Factory");
|
||||||
@@ -24,15 +27,15 @@ MainWindow::MainWindow(Simulation* sim, const GameConfig* config,
|
|||||||
|
|
||||||
m_headerBar = new HeaderBar(this);
|
m_headerBar = new HeaderBar(this);
|
||||||
|
|
||||||
m_gameWorldView = new GameWorldView(sim, config, visuals, this);
|
m_gameWorldView = new GameWorldView(sim, &sim->config(), &m_visuals, this);
|
||||||
|
|
||||||
m_bottomPanel = new QWidget(this);
|
m_bottomPanel = new QWidget(this);
|
||||||
QHBoxLayout* bottomLayout = new QHBoxLayout(m_bottomPanel);
|
QHBoxLayout* bottomLayout = new QHBoxLayout(m_bottomPanel);
|
||||||
bottomLayout->setContentsMargins(0, 0, 0, 0);
|
bottomLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
bottomLayout->setSpacing(0);
|
bottomLayout->setSpacing(0);
|
||||||
|
|
||||||
m_selectedBuildingPanel = new SelectedBuildingPanel(sim, config, m_bottomPanel);
|
m_selectedBuildingPanel = new SelectedBuildingPanel(sim, &sim->config(), m_bottomPanel);
|
||||||
m_buildButtonGrid = new BuildButtonGrid(config, m_bottomPanel);
|
m_buildButtonGrid = new BuildButtonGrid(&sim->config(), m_bottomPanel);
|
||||||
|
|
||||||
bottomLayout->addWidget(m_selectedBuildingPanel, 1);
|
bottomLayout->addWidget(m_selectedBuildingPanel, 1);
|
||||||
bottomLayout->addWidget(m_buildButtonGrid, 1);
|
bottomLayout->addWidget(m_buildButtonGrid, 1);
|
||||||
@@ -128,7 +131,20 @@ void MainWindow::onEscapeMenuRequested()
|
|||||||
QAbstractButton* clicked = box.clickedButton();
|
QAbstractButton* clicked = box.clickedButton();
|
||||||
if (clicked == restartBtn)
|
if (clicked == restartBtn)
|
||||||
{
|
{
|
||||||
m_sim->reset();
|
try
|
||||||
|
{
|
||||||
|
GameConfig newConfig = ConfigLoader::loadFromDirectory(m_configDir);
|
||||||
|
VisualsConfig newVisuals = VisualsLoader::load(m_configDir + "/visuals.toml");
|
||||||
|
m_visuals = std::move(newVisuals);
|
||||||
|
m_sim->reset(std::move(newConfig));
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, "Config Error",
|
||||||
|
QString("Failed to reload config:\n%1").arg(e.what()));
|
||||||
|
m_gameWorldView->setGameSpeed(prevSpeed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_gameWorldView->resetForNewGame();
|
m_gameWorldView->resetForNewGame();
|
||||||
}
|
}
|
||||||
else if (clicked == quitBtn)
|
else if (clicked == quitBtn)
|
||||||
@@ -159,7 +175,19 @@ void MainWindow::onGameOver()
|
|||||||
|
|
||||||
if (box.clickedButton() == restartBtn)
|
if (box.clickedButton() == restartBtn)
|
||||||
{
|
{
|
||||||
m_sim->reset();
|
try
|
||||||
|
{
|
||||||
|
GameConfig newConfig = ConfigLoader::loadFromDirectory(m_configDir);
|
||||||
|
VisualsConfig newVisuals = VisualsLoader::load(m_configDir + "/visuals.toml");
|
||||||
|
m_visuals = std::move(newVisuals);
|
||||||
|
m_sim->reset(std::move(newConfig));
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, "Config Error",
|
||||||
|
QString("Failed to reload config:\n%1").arg(e.what()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_gameWorldView->resetForNewGame();
|
m_gameWorldView->resetForNewGame();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "GameConfig.h"
|
|
||||||
#include "Tick.h"
|
#include "Tick.h"
|
||||||
#include "VisualsConfig.h"
|
#include "VisualsConfig.h"
|
||||||
|
|
||||||
@@ -18,8 +19,7 @@ class MainWindow : public QWidget
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MainWindow(Simulation* sim, const GameConfig* config,
|
MainWindow(Simulation* sim, const std::string& configDir, QWidget* parent = nullptr);
|
||||||
const VisualsConfig* visuals, QWidget* parent = nullptr);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
@@ -32,6 +32,8 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
void layoutPanels();
|
void layoutPanels();
|
||||||
|
|
||||||
|
std::string m_configDir;
|
||||||
|
VisualsConfig m_visuals;
|
||||||
Simulation* m_sim;
|
Simulation* m_sim;
|
||||||
GameWorldView* m_gameWorldView;
|
GameWorldView* m_gameWorldView;
|
||||||
HeaderBar* m_headerBar;
|
HeaderBar* m_headerBar;
|
||||||
|
|||||||
Reference in New Issue
Block a user