implement logging of arena states
This commit is contained in:
@@ -99,8 +99,23 @@ void ArenaWidget::resetToGrey()
|
||||
setStyleSheet("ArenaWidget { border: 2px solid #999999; padding: 8px; }");
|
||||
}
|
||||
|
||||
ArenaWidget::State ArenaWidget::getState() const
|
||||
{
|
||||
if (m_wasFinished)
|
||||
{
|
||||
return State::Ended;
|
||||
}
|
||||
if (m_running)
|
||||
{
|
||||
return State::Running;
|
||||
}
|
||||
return State::NotStarted;
|
||||
}
|
||||
|
||||
void ArenaWidget::updateStatus(const ArenaStatus& status)
|
||||
{
|
||||
m_lastStatus = status;
|
||||
|
||||
for (int ti = 0; ti < 2; ++ti)
|
||||
{
|
||||
const ArenaStatus::TeamStatus& team = status.teams[ti];
|
||||
|
||||
@@ -14,16 +14,27 @@ class ArenaWidget : public QFrame
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class State
|
||||
{
|
||||
NotStarted,
|
||||
Running,
|
||||
Ended
|
||||
};
|
||||
|
||||
ArenaWidget(int arenaIndex, const std::string& arenaName, QWidget* parent = nullptr);
|
||||
|
||||
void updateStatus(const ArenaStatus& status);
|
||||
void startSimulation();
|
||||
void resetToGrey();
|
||||
|
||||
const ArenaStatus& getLastStatus() const { return m_lastStatus; }
|
||||
State getState() const;
|
||||
|
||||
private:
|
||||
void buildLayout(const std::string& arenaName);
|
||||
|
||||
int m_arenaIndex;
|
||||
ArenaStatus m_lastStatus;
|
||||
QLabel* m_titleLabel;
|
||||
QLabel* m_team1Header;
|
||||
QLabel* m_team2Header;
|
||||
|
||||
@@ -1,13 +1,69 @@
|
||||
#include "BalancingWindow.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QFile>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QTextStream>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "ConfigLoader.h"
|
||||
#include "InspectWindow.h"
|
||||
#include "VisualsLoader.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// Escapes characters that would break a markdown table cell.
|
||||
QString escapeCell(const QString& text)
|
||||
{
|
||||
QString escaped = text;
|
||||
escaped.replace("|", "\\|");
|
||||
return escaped;
|
||||
}
|
||||
|
||||
QString stateText(ArenaWidget::State state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case ArenaWidget::State::NotStarted:
|
||||
return QStringLiteral("not started");
|
||||
case ArenaWidget::State::Running:
|
||||
return QStringLiteral("running");
|
||||
case ArenaWidget::State::Ended:
|
||||
return QStringLiteral("ended");
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
// Team column header: "[WON] Name — threat N", matching the arena widget.
|
||||
QString teamHeaderCell(const ArenaStatus& status, int teamIndex)
|
||||
{
|
||||
const ArenaStatus::TeamStatus& team = status.teams[teamIndex];
|
||||
QString header = QString::fromStdString(team.name);
|
||||
if (status.finished && status.winnerTeam == teamIndex)
|
||||
{
|
||||
header = QStringLiteral("[WON] ") + header;
|
||||
}
|
||||
header += QStringLiteral(" - threat %1").arg(QString::number(team.threatLevel, 'f', 0));
|
||||
return escapeCell(header);
|
||||
}
|
||||
|
||||
// Single entry line: "surviving/total DisplayName [L<level>]", matching the arena widget.
|
||||
QString entryCell(const ArenaStatus::Entry& entry)
|
||||
{
|
||||
QString cell = QString("%1/%2 %3")
|
||||
.arg(entry.surviving)
|
||||
.arg(entry.total)
|
||||
.arg(QString::fromStdString(entry.displayName));
|
||||
if (entry.level.has_value())
|
||||
{
|
||||
cell += QStringLiteral(" L%1").arg(entry.level.value());
|
||||
}
|
||||
return escapeCell(cell);
|
||||
}
|
||||
}
|
||||
|
||||
BalancingWindow::BalancingWindow(const BalancingConfig& balancingConfig,
|
||||
GameConfig gameConfig,
|
||||
const std::string& configDir,
|
||||
@@ -31,13 +87,16 @@ BalancingWindow::BalancingWindow(const BalancingConfig& balancingConfig,
|
||||
QHBoxLayout* buttonRow = new QHBoxLayout();
|
||||
m_reloadButton = new QPushButton(tr("Reload Config"), this);
|
||||
m_startAllButton = new QPushButton(tr("Start All"), this);
|
||||
m_logButton = new QPushButton(tr("Log"), this);
|
||||
buttonRow->addWidget(m_reloadButton);
|
||||
buttonRow->addWidget(m_startAllButton);
|
||||
buttonRow->addWidget(m_logButton);
|
||||
buttonRow->addStretch();
|
||||
mainLayout->addLayout(buttonRow);
|
||||
|
||||
connect(m_reloadButton, &QPushButton::clicked, this, &BalancingWindow::reloadConfig);
|
||||
connect(m_startAllButton, &QPushButton::clicked, this, &BalancingWindow::startAll);
|
||||
connect(m_logButton, &QPushButton::clicked, this, &BalancingWindow::writeLog);
|
||||
|
||||
m_scrollArea = new QScrollArea(this);
|
||||
m_scrollArea->setWidgetResizable(true);
|
||||
@@ -255,6 +314,7 @@ void BalancingWindow::setMainControlsEnabled(bool enabled)
|
||||
{
|
||||
m_reloadButton->setEnabled(enabled);
|
||||
m_startAllButton->setEnabled(enabled);
|
||||
m_logButton->setEnabled(enabled);
|
||||
for (ArenaEntry& entry : m_arenas)
|
||||
{
|
||||
for (QPushButton* btn : entry.widget->findChildren<QPushButton*>())
|
||||
@@ -291,4 +351,50 @@ void BalancingWindow::updateButtons()
|
||||
|
||||
m_reloadButton->setEnabled(!anyRunning);
|
||||
m_startAllButton->setEnabled(!allRunning);
|
||||
m_logButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void BalancingWindow::writeLog()
|
||||
{
|
||||
QFile file(QStringLiteral("balancing_log.md"));
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Log Failed"),
|
||||
tr("Could not open balancing_log.md for writing."));
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream out(&file);
|
||||
out.setCodec("UTF-8");
|
||||
|
||||
out << "# Balancing Log\n";
|
||||
|
||||
for (const ArenaEntry& entry : m_arenas)
|
||||
{
|
||||
const ArenaStatus& status = entry.widget->getLastStatus();
|
||||
|
||||
out << "\n## Arena: " << QString::fromStdString(entry.config.name)
|
||||
<< " (" << stateText(entry.widget->getState()) << ")\n\n";
|
||||
|
||||
out << "| " << teamHeaderCell(status, 0) << " | "
|
||||
<< teamHeaderCell(status, 1) << " |\n";
|
||||
out << "|---|---|\n";
|
||||
|
||||
const std::size_t rowCount = std::max(status.teams[0].entries.size(),
|
||||
status.teams[1].entries.size());
|
||||
for (std::size_t row = 0; row < rowCount; ++row)
|
||||
{
|
||||
QString leftCell;
|
||||
if (row < status.teams[0].entries.size())
|
||||
{
|
||||
leftCell = entryCell(status.teams[0].entries[row]);
|
||||
}
|
||||
QString rightCell;
|
||||
if (row < status.teams[1].entries.size())
|
||||
{
|
||||
rightCell = entryCell(status.teams[1].entries[row]);
|
||||
}
|
||||
out << "| " << leftCell << " | " << rightCell << " |\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ private slots:
|
||||
void pollStatuses();
|
||||
void reloadConfig();
|
||||
void startAll();
|
||||
void writeLog();
|
||||
|
||||
private:
|
||||
void startArena(int index);
|
||||
@@ -72,6 +73,7 @@ private:
|
||||
unsigned int m_nextSeed;
|
||||
QPushButton* m_reloadButton;
|
||||
QPushButton* m_startAllButton;
|
||||
QPushButton* m_logButton;
|
||||
QScrollArea* m_scrollArea;
|
||||
QTimer* m_pollTimer;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user