Files
dota_factory/src/balancing/BalancingWindow.cpp

295 lines
7.7 KiB
C++

#include "BalancingWindow.h"
#include <QHBoxLayout>
#include <QMessageBox>
#include <QVBoxLayout>
#include "ConfigLoader.h"
#include "InspectWindow.h"
#include "VisualsLoader.h"
BalancingWindow::BalancingWindow(const BalancingConfig& balancingConfig,
GameConfig gameConfig,
const std::string& configDir,
const std::string& balancingConfigPath,
QWidget* parent)
: QWidget(parent)
, m_gameConfig(std::move(gameConfig))
, m_configDir(configDir)
, m_balancingConfigPath(balancingConfigPath)
, m_nextSeed(0)
, m_inspectWindow(nullptr)
, m_inspectedArenaIndex(-1)
{
m_visuals = VisualsLoader::load(m_configDir + "/visuals.toml");
setWindowTitle(tr("DotaFactory — Balancing Tool"));
resize(800, 600);
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
QHBoxLayout* buttonRow = new QHBoxLayout();
m_reloadButton = new QPushButton(tr("Reload Config"), this);
m_startAllButton = new QPushButton(tr("Start All"), this);
buttonRow->addWidget(m_reloadButton);
buttonRow->addWidget(m_startAllButton);
buttonRow->addStretch();
mainLayout->addLayout(buttonRow);
connect(m_reloadButton, &QPushButton::clicked, this, &BalancingWindow::reloadConfig);
connect(m_startAllButton, &QPushButton::clicked, this, &BalancingWindow::startAll);
m_scrollArea = new QScrollArea(this);
m_scrollArea->setWidgetResizable(true);
mainLayout->addWidget(m_scrollArea);
populateArenas(balancingConfig);
m_pollTimer = new QTimer(this);
connect(m_pollTimer, &QTimer::timeout, this, &BalancingWindow::pollStatuses);
m_pollTimer->start(100);
registerForEvents();
}
BalancingWindow::~BalancingWindow()
{
unregisterForEvents();
m_pollTimer->stop();
if (m_inspectWindow)
{
delete m_inspectWindow;
m_inspectWindow = nullptr;
}
m_inspectedSim.reset();
stopAllArenas();
}
void BalancingWindow::populateArenas(const BalancingConfig& balancingConfig)
{
stopAllArenas();
m_arenas.clear();
QWidget* scrollContent = new QWidget(m_scrollArea);
QVBoxLayout* contentLayout = new QVBoxLayout(scrollContent);
contentLayout->setSpacing(8);
contentLayout->setContentsMargins(8, 8, 8, 8);
for (const ArenaConfig& arenaConfig : balancingConfig.arenas)
{
int index = static_cast<int>(m_arenas.size());
ArenaEntry entry;
entry.config = arenaConfig;
entry.simulation = std::make_unique<ArenaSimulation>(
m_gameConfig, arenaConfig, m_nextSeed++);
entry.widget = new ArenaWidget(index, arenaConfig.name, scrollContent);
contentLayout->addWidget(entry.widget);
entry.widget->updateStatus(entry.simulation->status());
m_arenas.push_back(std::move(entry));
}
contentLayout->addStretch();
m_scrollArea->setWidget(scrollContent);
updateButtons();
}
void BalancingWindow::stopAllArenas()
{
for (ArenaEntry& entry : m_arenas)
{
entry.simulation->requestStop();
}
for (ArenaEntry& entry : m_arenas)
{
if (entry.worker.joinable())
{
entry.worker.join();
}
}
}
void BalancingWindow::pollStatuses()
{
for (ArenaEntry& entry : m_arenas)
{
if (entry.worker.joinable())
{
const ArenaStatus status = entry.simulation->status();
entry.widget->updateStatus(status);
}
}
if (m_inspectedSim && m_inspectedArenaIndex >= 0)
{
const ArenaStatus status = m_inspectedSim->status();
m_arenas[static_cast<std::size_t>(m_inspectedArenaIndex)].widget->updateStatus(status);
}
updateButtons();
}
void BalancingWindow::reloadConfig()
{
try
{
GameConfig newGameConfig = ConfigLoader::loadFromDirectory(m_configDir);
BalancingConfig newBalancingConfig = loadBalancingConfig(m_balancingConfigPath);
m_gameConfig = std::move(newGameConfig);
populateArenas(newBalancingConfig);
}
catch (const std::exception& e)
{
QMessageBox::critical(this, tr("Reload Failed"), QString::fromStdString(e.what()));
}
}
void BalancingWindow::startAll()
{
for (int i = 0; i < static_cast<int>(m_arenas.size()); ++i)
{
startArena(i);
}
}
void BalancingWindow::handleEvent(std::shared_ptr<const ArenaStartRequestedEvent> event)
{
startArena(event->arenaIndex);
}
void BalancingWindow::handleEvent(std::shared_ptr<const ArenaInspectRequestedEvent> event)
{
inspectArena(event->arenaIndex);
}
void BalancingWindow::handleEvent(std::shared_ptr<const InspectWindowClosedEvent> /*event*/)
{
closeInspectWindow();
}
void BalancingWindow::startArena(int index)
{
ArenaEntry& entry = m_arenas[index];
if (entry.worker.joinable())
{
entry.simulation->requestStop();
entry.worker.join();
}
entry.simulation = std::make_unique<ArenaSimulation>(
m_gameConfig, entry.config, m_nextSeed++);
entry.widget->startSimulation();
entry.widget->updateStatus(entry.simulation->status());
ArenaSimulation* sim = entry.simulation.get();
entry.worker = std::thread([sim]() { sim->run(); });
updateButtons();
}
void BalancingWindow::inspectArena(int index)
{
if (m_inspectWindow)
{
delete m_inspectWindow;
m_inspectWindow = nullptr;
if (m_inspectedSim && m_inspectedArenaIndex >= 0
&& !m_inspectedSim->isFinished())
{
m_arenas[static_cast<std::size_t>(m_inspectedArenaIndex)].widget->resetToGrey();
}
m_inspectedSim.reset();
m_inspectedArenaIndex = -1;
}
ArenaEntry& entry = m_arenas[static_cast<std::size_t>(index)];
if (entry.worker.joinable())
{
entry.simulation->requestStop();
entry.worker.join();
}
m_inspectedSim = std::make_unique<ArenaSimulation>(
m_gameConfig, entry.config, m_nextSeed++);
m_inspectedArenaIndex = index;
entry.widget->resetToGrey();
entry.widget->startSimulation();
entry.widget->updateStatus(m_inspectedSim->status());
m_inspectWindow = new InspectWindow(
m_inspectedSim.get(), &m_gameConfig, &m_visuals, entry.config.name, nullptr);
setMainControlsEnabled(false);
m_inspectWindow->show();
}
void BalancingWindow::closeInspectWindow()
{
if (!m_inspectWindow)
{
return;
}
m_inspectWindow->deleteLater();
m_inspectWindow = nullptr;
if (m_inspectedArenaIndex >= 0 && m_inspectedSim)
{
if (!m_inspectedSim->isFinished())
{
m_arenas[static_cast<std::size_t>(m_inspectedArenaIndex)].widget->resetToGrey();
}
}
m_inspectedSim.reset();
m_inspectedArenaIndex = -1;
setMainControlsEnabled(true);
updateButtons();
}
void BalancingWindow::setMainControlsEnabled(bool enabled)
{
m_reloadButton->setEnabled(enabled);
m_startAllButton->setEnabled(enabled);
for (ArenaEntry& entry : m_arenas)
{
for (QPushButton* btn : entry.widget->findChildren<QPushButton*>())
{
btn->setEnabled(enabled);
}
}
}
void BalancingWindow::updateButtons()
{
if (m_inspectWindow)
{
return;
}
bool anyRunning = false;
bool allRunning = true;
for (ArenaEntry& entry : m_arenas)
{
if (entry.worker.joinable() && !entry.simulation->status().finished)
{
anyRunning = true;
}
else
{
allRunning = false;
}
}
if (m_arenas.empty())
{
allRunning = false;
}
m_reloadButton->setEnabled(!anyRunning);
m_startAllButton->setEnabled(!allRunning);
}