Tons of crap
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
build/
|
build/
|
||||||
|
build-codex/
|
||||||
|
.codex
|
||||||
793
mainwindow.cpp
793
mainwindow.cpp
@@ -1,12 +1,29 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QIntValidator>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent)
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
: QMainWindow(parent), socket(new QTcpSocket(this)) {
|
: QMainWindow(parent), socket(new QTcpSocket(this)) {
|
||||||
setupUI();
|
setupUI();
|
||||||
|
updateConnectionStatus();
|
||||||
|
loadSavedServers();
|
||||||
statusTimer = new QTimer(this);
|
statusTimer = new QTimer(this);
|
||||||
|
lockedTimeTimer = new QTimer(this);
|
||||||
connect(statusTimer, &QTimer::timeout, this, &MainWindow::updateConnectionStatus);
|
connect(statusTimer, &QTimer::timeout, this, &MainWindow::updateConnectionStatus);
|
||||||
|
connect(lockedTimeTimer, &QTimer::timeout, this, &MainWindow::resendLockedServerTime);
|
||||||
statusTimer->start(1000);
|
statusTimer->start(1000);
|
||||||
connect(socket, &QTcpSocket::readyRead, this, &MainWindow::readServerOutput);
|
connect(socket, &QTcpSocket::readyRead, this, &MainWindow::readServerOutput);
|
||||||
}
|
}
|
||||||
@@ -36,6 +53,25 @@ void MainWindow::readServerOutput() {
|
|||||||
QString text = QString::fromUtf8(response);
|
QString text = QString::fromUtf8(response);
|
||||||
serverLogTextEdit->append(text);
|
serverLogTextEdit->append(text);
|
||||||
|
|
||||||
|
if (awaitingUsersResponse) {
|
||||||
|
usersResponseBuffer += text;
|
||||||
|
if (usersResponseBuffer.contains(QRegularExpression(R"(Total of \d+ in the game)"))) {
|
||||||
|
parseUsersResponse(usersResponseBuffer);
|
||||||
|
usersResponseBuffer.clear();
|
||||||
|
awaitingUsersResponse = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (awaitingBansResponse) {
|
||||||
|
bansResponseBuffer += text;
|
||||||
|
if (bansResponseBuffer.contains("Ban list entries:") &&
|
||||||
|
bansResponseBuffer.contains(QRegularExpression(R"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} - )"))) {
|
||||||
|
parseBansResponse(bansResponseBuffer);
|
||||||
|
bansResponseBuffer.clear();
|
||||||
|
awaitingBansResponse = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (text.contains("Please enter password:", Qt::CaseInsensitive)) {
|
if (text.contains("Please enter password:", Qt::CaseInsensitive)) {
|
||||||
socket->write(passwordEdit->text().toUtf8() + "\n");
|
socket->write(passwordEdit->text().toUtf8() + "\n");
|
||||||
socket->waitForBytesWritten(1000);
|
socket->waitForBytesWritten(1000);
|
||||||
@@ -47,26 +83,485 @@ void MainWindow::readServerOutput() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::sendTelnetCommand(const QString &command) {
|
bool MainWindow::sendTelnetCommand(const QString &command) {
|
||||||
if (socket->state() != QAbstractSocket::ConnectedState) {
|
if (socket->state() != QAbstractSocket::ConnectedState) {
|
||||||
QMessageBox::warning(this, "Not Connected", "Please connect to the server first.");
|
QMessageBox::warning(this, "Not Connected", "Please connect to the server first.");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (!isAuthenticated) {
|
if (!isAuthenticated) {
|
||||||
QMessageBox::warning(this, "Not Authenticated", "Server is waiting for a password. Please wait or reconnect.");
|
QMessageBox::warning(this, "Not Authenticated", "Server is waiting for a password. Please wait or reconnect.");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
socket->write(command.toUtf8() + "\n");
|
socket->write(command.toUtf8() + "\n");
|
||||||
socket->waitForBytesWritten(1000);
|
socket->waitForBytesWritten(1000);
|
||||||
historyTextEdit->append(command);
|
const QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
|
||||||
|
historyTextEdit->append(QString("[%1] %2").arg(timestamp, command));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MainWindow::serverConfigFilePath() const {
|
||||||
|
const QString configRoot = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
|
||||||
|
return QDir(configRoot).filePath("7d2d-commandutil/servers.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::loadSavedServers() {
|
||||||
|
savedServers.clear();
|
||||||
|
savedServersCombo->clear();
|
||||||
|
savedServersCombo->addItem("Select Server");
|
||||||
|
savedServersCombo->setCurrentIndex(0);
|
||||||
|
|
||||||
|
QFile file(serverConfigFilePath());
|
||||||
|
if (!file.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
QMessageBox::warning(this, "Load Failed", "Could not open saved servers file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmlStreamReader xml(&file);
|
||||||
|
while (!xml.atEnd()) {
|
||||||
|
xml.readNext();
|
||||||
|
if (!xml.isStartElement() || xml.name() != "server") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SavedServerEntry entry;
|
||||||
|
entry.name = xml.attributes().value("name").toString();
|
||||||
|
|
||||||
|
while (!(xml.isEndElement() && xml.name() == "server") && !xml.atEnd()) {
|
||||||
|
xml.readNext();
|
||||||
|
if (!xml.isStartElement()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xml.name() == "host") {
|
||||||
|
entry.server = xml.readElementText();
|
||||||
|
} else if (xml.name() == "port") {
|
||||||
|
entry.port = xml.readElementText();
|
||||||
|
} else if (xml.name() == "password") {
|
||||||
|
entry.password = xml.readElementText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry.name.isEmpty()) {
|
||||||
|
savedServers.append(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xml.hasError()) {
|
||||||
|
QMessageBox::warning(this, "Load Failed", "The saved servers file is not valid XML.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(savedServers.begin(), savedServers.end(), [](const SavedServerEntry &left, const SavedServerEntry &right) {
|
||||||
|
return QString::compare(left.name, right.name, Qt::CaseInsensitive) < 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const SavedServerEntry &entry : savedServers) {
|
||||||
|
savedServersCombo->addItem(entry.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::parseUsersResponse(const QString &text) {
|
||||||
|
static const QRegularExpression userLinePattern(
|
||||||
|
R"(^\d+\.\s+id=([^,]+),\s+([^,]+),\s+pos=\(([^)]*)\),\s+rot=\(([^)]*)\),\s+remote=([^,]+),\s+health=([^,]+),\s+deaths=([^,]+),\s+zombies=([^,]+),\s+players=([^,]+),\s+score=([^,]+),\s+level=([^,]+),\s+pltfmid=([^,]+),\s+crossid=([^,]+),\s+ip=([^,]+),\s+ping=([^,\s]+)\s*$)"
|
||||||
|
);
|
||||||
|
|
||||||
|
users.clear();
|
||||||
|
usersListWidget->clear();
|
||||||
|
clearUserInfo();
|
||||||
|
|
||||||
|
const QStringList lines = text.split(QRegularExpression(R"(\r?\n)"), Qt::SkipEmptyParts);
|
||||||
|
for (const QString &line : lines) {
|
||||||
|
const QRegularExpressionMatch match = userLinePattern.match(line.trimmed());
|
||||||
|
if (!match.hasMatch()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserEntry entry{
|
||||||
|
match.captured(1).trimmed(),
|
||||||
|
match.captured(2).trimmed(),
|
||||||
|
match.captured(3).trimmed(),
|
||||||
|
match.captured(4).trimmed(),
|
||||||
|
match.captured(5).trimmed(),
|
||||||
|
match.captured(6).trimmed(),
|
||||||
|
match.captured(7).trimmed(),
|
||||||
|
match.captured(8).trimmed(),
|
||||||
|
match.captured(9).trimmed(),
|
||||||
|
match.captured(10).trimmed(),
|
||||||
|
match.captured(11).trimmed(),
|
||||||
|
match.captured(12).trimmed(),
|
||||||
|
match.captured(13).trimmed(),
|
||||||
|
match.captured(14).trimmed(),
|
||||||
|
match.captured(15).trimmed()
|
||||||
|
};
|
||||||
|
users.append(entry);
|
||||||
|
usersListWidget->addItem(entry.username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::clearUserInfo() {
|
||||||
|
for (QLabel *label : userInfoValueLabels) {
|
||||||
|
label->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::clearBanInfo() {
|
||||||
|
for (QLabel *label : banInfoValueLabels) {
|
||||||
|
label->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::refreshUsers() {
|
||||||
|
users.clear();
|
||||||
|
usersListWidget->clear();
|
||||||
|
usersResponseBuffer.clear();
|
||||||
|
clearUserInfo();
|
||||||
|
|
||||||
|
if (!sendTelnetCommand("lp")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
awaitingUsersResponse = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::displaySelectedUserInfo(int row) {
|
||||||
|
if (row < 0 || row >= users.size()) {
|
||||||
|
clearUserInfo();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserEntry &entry = users.at(row);
|
||||||
|
userInfoValueLabels.value("Player ID")->setText(entry.playerId);
|
||||||
|
userInfoValueLabels.value("Username")->setText(entry.username);
|
||||||
|
userInfoValueLabels.value("Position")->setText(entry.position);
|
||||||
|
userInfoValueLabels.value("Rotation")->setText(entry.rotation);
|
||||||
|
userInfoValueLabels.value("Remote")->setText(entry.remoteState);
|
||||||
|
userInfoValueLabels.value("Health")->setText(entry.health);
|
||||||
|
userInfoValueLabels.value("Deaths")->setText(entry.deaths);
|
||||||
|
userInfoValueLabels.value("Zombies")->setText(entry.zombies);
|
||||||
|
userInfoValueLabels.value("Players")->setText(entry.players);
|
||||||
|
userInfoValueLabels.value("Score")->setText(entry.score);
|
||||||
|
userInfoValueLabels.value("Level")->setText(entry.level);
|
||||||
|
userInfoValueLabels.value("Platform ID")->setText(entry.platformId);
|
||||||
|
userInfoValueLabels.value("EOS ID")->setText(entry.eosId);
|
||||||
|
userInfoValueLabels.value("IP Address")->setText(entry.ipAddress);
|
||||||
|
userInfoValueLabels.value("Ping")->setText(entry.ping);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::parseBansResponse(const QString &text) {
|
||||||
|
static const QRegularExpression banLinePattern(
|
||||||
|
R"(^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) - ([^(]+) \(([^)]*)\) - (.*)$)"
|
||||||
|
);
|
||||||
|
|
||||||
|
bans.clear();
|
||||||
|
bansListWidget->clear();
|
||||||
|
clearBanInfo();
|
||||||
|
|
||||||
|
const QStringList lines = text.split(QRegularExpression(R"(\r?\n)"), Qt::SkipEmptyParts);
|
||||||
|
for (const QString &line : lines) {
|
||||||
|
const QRegularExpressionMatch match = banLinePattern.match(line.trimmed());
|
||||||
|
if (!match.hasMatch()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BanEntry entry{
|
||||||
|
match.captured(1).trimmed(),
|
||||||
|
match.captured(2).trimmed(),
|
||||||
|
match.captured(3).trimmed(),
|
||||||
|
match.captured(4).trimmed()
|
||||||
|
};
|
||||||
|
bans.append(entry);
|
||||||
|
bansListWidget->addItem(entry.username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::refreshBans() {
|
||||||
|
bans.clear();
|
||||||
|
bansListWidget->clear();
|
||||||
|
bansResponseBuffer.clear();
|
||||||
|
clearBanInfo();
|
||||||
|
|
||||||
|
if (!sendTelnetCommand("ban list")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
awaitingBansResponse = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::displaySelectedBanInfo(int row) {
|
||||||
|
if (row < 0 || row >= bans.size()) {
|
||||||
|
clearBanInfo();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BanEntry &entry = bans.at(row);
|
||||||
|
banInfoValueLabels.value("Banned Until")->setText(entry.bannedUntil);
|
||||||
|
banInfoValueLabels.value("Ban Reason")->setText(entry.reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::removeSelectedBan() {
|
||||||
|
const int row = bansListWidget->currentRow();
|
||||||
|
if (row < 0 || row >= bans.size()) {
|
||||||
|
QMessageBox::warning(this, "No Ban Selected", "Please select a banned user first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTelnetCommand(QString("ban remove %1").arg(bans.at(row).userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::kickSelectedUser() {
|
||||||
|
const int row = usersListWidget->currentRow();
|
||||||
|
if (row < 0 || row >= users.size()) {
|
||||||
|
QMessageBox::warning(this, "No User Selected", "Please select a user first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
const QString reason = QInputDialog::getText(
|
||||||
|
this,
|
||||||
|
"Kick User",
|
||||||
|
"Reason?",
|
||||||
|
QLineEdit::Normal,
|
||||||
|
QString(),
|
||||||
|
&ok
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString trimmedReason = reason.trimmed();
|
||||||
|
const QString playerId = users.at(row).playerId;
|
||||||
|
QString escapedReason = trimmedReason;
|
||||||
|
const QString command = trimmedReason.isEmpty()
|
||||||
|
? QString("kick %1").arg(playerId)
|
||||||
|
: QString("kick %1 \"%2\"").arg(playerId, escapedReason.replace("\"", "\\\""));
|
||||||
|
sendTelnetCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::banSelectedUser() {
|
||||||
|
const int row = usersListWidget->currentRow();
|
||||||
|
if (row < 0 || row >= users.size()) {
|
||||||
|
QMessageBox::warning(this, "No User Selected", "Please select a user first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog dialog(this);
|
||||||
|
dialog.setWindowTitle("Ban User");
|
||||||
|
|
||||||
|
QVBoxLayout *dialogLayout = new QVBoxLayout(&dialog);
|
||||||
|
|
||||||
|
QHBoxLayout *durationLayout = new QHBoxLayout();
|
||||||
|
QLineEdit *durationEdit = new QLineEdit();
|
||||||
|
durationEdit->setValidator(new QIntValidator(0, 999999999, durationEdit));
|
||||||
|
QComboBox *durationUnitCombo = new QComboBox();
|
||||||
|
durationUnitCombo->addItems({"minutes", "hours", "days", "weeks", "months", "years"});
|
||||||
|
durationLayout->addWidget(durationEdit);
|
||||||
|
durationLayout->addWidget(durationUnitCombo);
|
||||||
|
dialogLayout->addLayout(durationLayout);
|
||||||
|
|
||||||
|
QHBoxLayout *reasonLayout = new QHBoxLayout();
|
||||||
|
reasonLayout->addWidget(new QLabel("Reason"));
|
||||||
|
QLineEdit *reasonEdit = new QLineEdit();
|
||||||
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
reasonLayout->addWidget(reasonEdit);
|
||||||
|
reasonLayout->addWidget(buttonBox);
|
||||||
|
dialogLayout->addLayout(reasonLayout);
|
||||||
|
|
||||||
|
connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||||
|
|
||||||
|
if (dialog.exec() != QDialog::Accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString duration = durationEdit->text().trimmed();
|
||||||
|
if (duration.isEmpty()) {
|
||||||
|
QMessageBox::warning(this, "Invalid Duration", "Please enter a duration.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString playerId = users.at(row).playerId;
|
||||||
|
QString escapedReason = reasonEdit->text().trimmed();
|
||||||
|
const QString command = QString("ban add %1 %2 %3 \"%4\"")
|
||||||
|
.arg(playerId, duration, durationUnitCombo->currentText(), escapedReason.replace("\"", "\\\""));
|
||||||
|
sendTelnetCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::writeSavedServers() const {
|
||||||
|
const QString configFile = serverConfigFilePath();
|
||||||
|
QDir configDir = QFileInfo(configFile).dir();
|
||||||
|
if (!configDir.exists() && !configDir.mkpath(".")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(configFile);
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QXmlStreamWriter xml(&file);
|
||||||
|
xml.setAutoFormatting(true);
|
||||||
|
xml.writeStartDocument();
|
||||||
|
xml.writeStartElement("servers");
|
||||||
|
|
||||||
|
for (const SavedServerEntry &entry : savedServers) {
|
||||||
|
xml.writeStartElement("server");
|
||||||
|
xml.writeAttribute("name", entry.name);
|
||||||
|
xml.writeTextElement("host", entry.server);
|
||||||
|
xml.writeTextElement("port", entry.port);
|
||||||
|
xml.writeTextElement("password", entry.password);
|
||||||
|
xml.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.writeEndElement();
|
||||||
|
xml.writeEndDocument();
|
||||||
|
return !xml.hasError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::saveServerEntry() {
|
||||||
|
const QString server = serverEdit->text().trimmed();
|
||||||
|
const QString port = portEdit->text().trimmed();
|
||||||
|
|
||||||
|
if (server.isEmpty() || port.isEmpty()) {
|
||||||
|
QMessageBox::warning(this, "Missing Information", "Server and port must be filled in before saving.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
const QString name = QInputDialog::getText(
|
||||||
|
this,
|
||||||
|
"Save Server",
|
||||||
|
"Server name:",
|
||||||
|
QLineEdit::Normal,
|
||||||
|
QString(),
|
||||||
|
&ok
|
||||||
|
).trimmed();
|
||||||
|
|
||||||
|
if (!ok || name.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SavedServerEntry entry{name, server, port, passwordEdit->text()};
|
||||||
|
bool replaced = false;
|
||||||
|
for (SavedServerEntry &savedEntry : savedServers) {
|
||||||
|
if (savedEntry.name == name) {
|
||||||
|
savedEntry = entry;
|
||||||
|
replaced = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!replaced) {
|
||||||
|
savedServers.append(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!writeSavedServers()) {
|
||||||
|
QMessageBox::warning(this, "Save Failed", "Could not write the saved servers file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSavedServers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::loadSelectedServer() {
|
||||||
|
const int index = savedServersCombo->currentIndex() - 1;
|
||||||
|
if (index < 0 || index >= savedServers.size()) {
|
||||||
|
QMessageBox::warning(this, "Load Failed", "Please select a saved server first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SavedServerEntry &entry = savedServers.at(index);
|
||||||
|
serverEdit->setText(entry.server);
|
||||||
|
portEdit->setText(entry.port);
|
||||||
|
passwordEdit->setText(entry.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::deleteSelectedServer() {
|
||||||
|
const int index = savedServersCombo->currentIndex() - 1;
|
||||||
|
if (index < 0 || index >= savedServers.size()) {
|
||||||
|
QMessageBox::warning(this, "Delete Failed", "Please select a saved server first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
savedServers.removeAt(index);
|
||||||
|
if (!writeSavedServers()) {
|
||||||
|
QMessageBox::warning(this, "Delete Failed", "Could not update the saved servers file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSavedServers();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::sendValidatedTimeCommand() {
|
||||||
|
bool dayOk = false;
|
||||||
|
bool hourOk = false;
|
||||||
|
bool minuteOk = false;
|
||||||
|
const int day = dayEdit->text().toInt(&dayOk);
|
||||||
|
const int hour = hourEdit->text().toInt(&hourOk);
|
||||||
|
const int minute = minuteEdit->text().toInt(&minuteOk);
|
||||||
|
|
||||||
|
if (!dayOk || !hourOk || !minuteOk || day < 0 || day > 9999 || hour < 0 || hour > 23 || minute < 0 || minute > 59) {
|
||||||
|
QMessageBox::warning(this, "Invalid Time", "Invalid Time");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString cmd = QString("st %1 %2 %3")
|
||||||
|
.arg(day)
|
||||||
|
.arg(hour)
|
||||||
|
.arg(minute);
|
||||||
|
return sendTelnetCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::sendTimeCommand() {
|
void MainWindow::sendTimeCommand() {
|
||||||
QString cmd = QString("st %1 %2 %3")
|
sendValidatedTimeCommand();
|
||||||
.arg(dayEdit->text())
|
}
|
||||||
.arg(hourEdit->text())
|
|
||||||
.arg(minuteEdit->text());
|
void MainWindow::updateServerTimeLockState(bool locked) {
|
||||||
sendTelnetCommand(cmd);
|
isServerTimeLocked = locked;
|
||||||
|
dayEdit->setEnabled(!locked);
|
||||||
|
hourEdit->setEnabled(!locked);
|
||||||
|
minuteEdit->setEnabled(!locked);
|
||||||
|
|
||||||
|
QPalette palette = serverTimeStatusLabel->palette();
|
||||||
|
if (locked) {
|
||||||
|
serverTimeStatusLabel->setText("Server Time Locked");
|
||||||
|
serverTimeLockButton->setText("Unlock Server Time");
|
||||||
|
palette.setColor(QPalette::WindowText, Qt::red);
|
||||||
|
} else {
|
||||||
|
serverTimeStatusLabel->setText("Server Time Unlocked");
|
||||||
|
serverTimeLockButton->setText("Lock Server Time");
|
||||||
|
palette.setColor(QPalette::WindowText, Qt::darkGreen);
|
||||||
|
}
|
||||||
|
serverTimeStatusLabel->setPalette(palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::lockServerTime() {
|
||||||
|
if (!sendValidatedTimeCommand()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lockedTimeTimer->start(5000);
|
||||||
|
updateServerTimeLockState(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::unlockServerTime() {
|
||||||
|
if (!isServerTimeLocked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lockedTimeTimer->stop();
|
||||||
|
updateServerTimeLockState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::resendLockedServerTime() {
|
||||||
|
if (!isServerTimeLocked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendValidatedTimeCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::sendSpeedCommand() {
|
void MainWindow::sendSpeedCommand() {
|
||||||
@@ -90,14 +585,18 @@ void MainWindow::sendCustomCommand() {
|
|||||||
|
|
||||||
void MainWindow::updateConnectionStatus() {
|
void MainWindow::updateConnectionStatus() {
|
||||||
QPalette palette;
|
QPalette palette;
|
||||||
|
QString connectionStatus;
|
||||||
if (socket->state() == QAbstractSocket::ConnectedState) {
|
if (socket->state() == QAbstractSocket::ConnectedState) {
|
||||||
connectionStatusLabel->setText("Connected");
|
connectionStatus = "Connected";
|
||||||
|
connectionStatusLabel->setText(connectionStatus);
|
||||||
palette.setColor(QPalette::WindowText, Qt::darkGreen);
|
palette.setColor(QPalette::WindowText, Qt::darkGreen);
|
||||||
} else {
|
} else {
|
||||||
connectionStatusLabel->setText("Disconnected");
|
connectionStatus = "Disconnected";
|
||||||
|
connectionStatusLabel->setText(connectionStatus);
|
||||||
palette.setColor(QPalette::WindowText, Qt::red);
|
palette.setColor(QPalette::WindowText, Qt::red);
|
||||||
}
|
}
|
||||||
connectionStatusLabel->setPalette(palette);
|
connectionStatusLabel->setPalette(palette);
|
||||||
|
setWindowTitle(QString("7D2D-CommandUtil - %1").arg(connectionStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::disconnectFromServer() {
|
void MainWindow::disconnectFromServer() {
|
||||||
@@ -122,6 +621,186 @@ void MainWindow::setupUI() {
|
|||||||
QWidget *mainTab = new QWidget;
|
QWidget *mainTab = new QWidget;
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout(mainTab);
|
QVBoxLayout *mainLayout = new QVBoxLayout(mainTab);
|
||||||
|
|
||||||
|
QIntValidator *dayValidator = new QIntValidator(0, 9999, this);
|
||||||
|
QIntValidator *hourValidator = new QIntValidator(0, 23, this);
|
||||||
|
QIntValidator *minuteValidator = new QIntValidator(0, 59, this);
|
||||||
|
|
||||||
|
QGroupBox *timeBox = new QGroupBox("Set Server Time");
|
||||||
|
QVBoxLayout *timeBoxLayout = new QVBoxLayout(timeBox);
|
||||||
|
serverTimeStatusLabel = new QLabel("Server Time Unlocked");
|
||||||
|
serverTimeStatusLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
timeBoxLayout->addWidget(serverTimeStatusLabel);
|
||||||
|
|
||||||
|
QHBoxLayout *timeLayout = new QHBoxLayout();
|
||||||
|
dayEdit = new QLineEdit(); dayEdit->setMaxLength(4); dayEdit->setValidator(dayValidator);
|
||||||
|
hourEdit = new QLineEdit(); hourEdit->setMaxLength(2); hourEdit->setValidator(hourValidator);
|
||||||
|
minuteEdit = new QLineEdit(); minuteEdit->setMaxLength(2); minuteEdit->setValidator(minuteValidator);
|
||||||
|
QPushButton *timeButton = new QPushButton("Set Server Time");
|
||||||
|
connect(timeButton, &QPushButton::clicked, this, &MainWindow::sendTimeCommand);
|
||||||
|
timeLayout->addWidget(new QLabel("Day:"));
|
||||||
|
timeLayout->addWidget(dayEdit);
|
||||||
|
timeLayout->addWidget(new QLabel("Hour:"));
|
||||||
|
timeLayout->addWidget(hourEdit);
|
||||||
|
timeLayout->addWidget(new QLabel("Minute:"));
|
||||||
|
timeLayout->addWidget(minuteEdit);
|
||||||
|
timeLayout->addStretch();
|
||||||
|
timeLayout->addWidget(timeButton);
|
||||||
|
timeBoxLayout->addLayout(timeLayout);
|
||||||
|
|
||||||
|
QHBoxLayout *timeLockButtonLayout = new QHBoxLayout();
|
||||||
|
serverTimeLockButton = new QPushButton("Lock Server Time");
|
||||||
|
connect(serverTimeLockButton, &QPushButton::clicked, this, [this]() {
|
||||||
|
if (isServerTimeLocked) {
|
||||||
|
unlockServerTime();
|
||||||
|
} else {
|
||||||
|
lockServerTime();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
timeLockButtonLayout->addStretch();
|
||||||
|
timeLockButtonLayout->addWidget(serverTimeLockButton);
|
||||||
|
timeLockButtonLayout->addStretch();
|
||||||
|
timeBoxLayout->addLayout(timeLockButtonLayout);
|
||||||
|
mainLayout->addWidget(timeBox);
|
||||||
|
updateServerTimeLockState(false);
|
||||||
|
|
||||||
|
QGroupBox *speedBox = new QGroupBox("Set Game Speed");
|
||||||
|
QVBoxLayout *speedLayout = new QVBoxLayout(speedBox);
|
||||||
|
QHBoxLayout *sliderLayout = new QHBoxLayout();
|
||||||
|
speedSlider = new QSlider(Qt::Horizontal);
|
||||||
|
speedSlider->setMinimum(1);
|
||||||
|
speedSlider->setMaximum(5);
|
||||||
|
speedSlider->setTickInterval(1);
|
||||||
|
speedSlider->setTickPosition(QSlider::TicksBelow);
|
||||||
|
connect(speedSlider, &QSlider::valueChanged, this, &MainWindow::updateSliderLabel);
|
||||||
|
sliderLayout->addWidget(speedSlider);
|
||||||
|
QPushButton *speedButton = new QPushButton("Set Time Speed");
|
||||||
|
connect(speedButton, &QPushButton::clicked, this, &MainWindow::sendSpeedCommand);
|
||||||
|
sliderLayout->addWidget(speedButton);
|
||||||
|
sliderLabel = new QLabel("60");
|
||||||
|
sliderLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
speedLayout->addLayout(sliderLayout);
|
||||||
|
speedLayout->addWidget(sliderLabel);
|
||||||
|
mainLayout->addWidget(speedBox);
|
||||||
|
|
||||||
|
tabWidget->addTab(mainTab, "Time");
|
||||||
|
|
||||||
|
QWidget *usersTab = new QWidget;
|
||||||
|
QHBoxLayout *usersTabLayout = new QHBoxLayout(usersTab);
|
||||||
|
QVBoxLayout *usersLeftLayout = new QVBoxLayout();
|
||||||
|
|
||||||
|
QGroupBox *usersBox = new QGroupBox("Users");
|
||||||
|
QVBoxLayout *usersBoxLayout = new QVBoxLayout(usersBox);
|
||||||
|
usersListWidget = new QListWidget();
|
||||||
|
QPushButton *refreshUsersButton = new QPushButton("Refresh");
|
||||||
|
connect(usersListWidget, &QListWidget::currentRowChanged, this, &MainWindow::displaySelectedUserInfo);
|
||||||
|
connect(refreshUsersButton, &QPushButton::clicked, this, &MainWindow::refreshUsers);
|
||||||
|
usersBoxLayout->addWidget(usersListWidget);
|
||||||
|
usersBoxLayout->addWidget(refreshUsersButton);
|
||||||
|
usersLeftLayout->addWidget(usersBox);
|
||||||
|
|
||||||
|
QGroupBox *actionsBox = new QGroupBox("Actions");
|
||||||
|
QVBoxLayout *actionsBoxLayout = new QVBoxLayout(actionsBox);
|
||||||
|
QPushButton *kickUserButton = new QPushButton("Kick");
|
||||||
|
QPushButton *banUserButton = new QPushButton("Ban");
|
||||||
|
connect(kickUserButton, &QPushButton::clicked, this, &MainWindow::kickSelectedUser);
|
||||||
|
connect(banUserButton, &QPushButton::clicked, this, &MainWindow::banSelectedUser);
|
||||||
|
actionsBoxLayout->addWidget(kickUserButton);
|
||||||
|
actionsBoxLayout->addWidget(banUserButton);
|
||||||
|
actionsBoxLayout->addStretch();
|
||||||
|
usersLeftLayout->addWidget(actionsBox);
|
||||||
|
|
||||||
|
QGroupBox *userInfoBox = new QGroupBox("User Info");
|
||||||
|
QFormLayout *userInfoBoxLayout = new QFormLayout(userInfoBox);
|
||||||
|
const QStringList userInfoFields = {
|
||||||
|
"Player ID", "Username", "Position", "Rotation", "Remote",
|
||||||
|
"Health", "Deaths", "Zombies", "Players", "Score",
|
||||||
|
"Level", "Platform ID", "EOS ID", "IP Address", "Ping"
|
||||||
|
};
|
||||||
|
for (const QString &fieldName : userInfoFields) {
|
||||||
|
QLabel *valueLabel = new QLabel();
|
||||||
|
valueLabel->setWordWrap(true);
|
||||||
|
valueLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
|
valueLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||||
|
userInfoValueLabels.insert(fieldName, valueLabel);
|
||||||
|
userInfoBoxLayout->addRow(fieldName + ":", valueLabel);
|
||||||
|
}
|
||||||
|
clearUserInfo();
|
||||||
|
|
||||||
|
usersTabLayout->addLayout(usersLeftLayout, 1);
|
||||||
|
usersTabLayout->addWidget(userInfoBox, 1);
|
||||||
|
tabWidget->addTab(usersTab, "Users");
|
||||||
|
|
||||||
|
QWidget *bansTab = new QWidget;
|
||||||
|
QHBoxLayout *bansTabLayout = new QHBoxLayout(bansTab);
|
||||||
|
QVBoxLayout *bansLeftLayout = new QVBoxLayout();
|
||||||
|
|
||||||
|
QGroupBox *bansBox = new QGroupBox("Bans");
|
||||||
|
QVBoxLayout *bansBoxLayout = new QVBoxLayout(bansBox);
|
||||||
|
bansListWidget = new QListWidget();
|
||||||
|
QPushButton *refreshBansButton = new QPushButton("Refresh");
|
||||||
|
connect(bansListWidget, &QListWidget::currentRowChanged, this, &MainWindow::displaySelectedBanInfo);
|
||||||
|
connect(refreshBansButton, &QPushButton::clicked, this, &MainWindow::refreshBans);
|
||||||
|
bansBoxLayout->addWidget(bansListWidget);
|
||||||
|
bansBoxLayout->addWidget(refreshBansButton);
|
||||||
|
bansLeftLayout->addWidget(bansBox);
|
||||||
|
|
||||||
|
QGroupBox *banActionsBox = new QGroupBox("Actions");
|
||||||
|
QVBoxLayout *banActionsBoxLayout = new QVBoxLayout(banActionsBox);
|
||||||
|
QPushButton *removeBanButton = new QPushButton("Remove");
|
||||||
|
connect(removeBanButton, &QPushButton::clicked, this, &MainWindow::removeSelectedBan);
|
||||||
|
banActionsBoxLayout->addWidget(removeBanButton);
|
||||||
|
banActionsBoxLayout->addStretch();
|
||||||
|
bansLeftLayout->addWidget(banActionsBox);
|
||||||
|
|
||||||
|
QGroupBox *banInfoBox = new QGroupBox("Ban Info");
|
||||||
|
QFormLayout *banInfoBoxLayout = new QFormLayout(banInfoBox);
|
||||||
|
const QStringList banInfoFields = {"Banned Until", "Ban Reason"};
|
||||||
|
for (const QString &fieldName : banInfoFields) {
|
||||||
|
QLabel *valueLabel = new QLabel();
|
||||||
|
valueLabel->setWordWrap(true);
|
||||||
|
valueLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
|
valueLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||||
|
banInfoValueLabels.insert(fieldName, valueLabel);
|
||||||
|
banInfoBoxLayout->addRow(fieldName + ":", valueLabel);
|
||||||
|
}
|
||||||
|
clearBanInfo();
|
||||||
|
|
||||||
|
bansTabLayout->addLayout(bansLeftLayout, 1);
|
||||||
|
bansTabLayout->addWidget(banInfoBox, 1);
|
||||||
|
tabWidget->addTab(bansTab, "Bans");
|
||||||
|
|
||||||
|
QWidget *worldTab = new QWidget;
|
||||||
|
tabWidget->addTab(worldTab, "World");
|
||||||
|
|
||||||
|
QWidget *historyTab = new QWidget;
|
||||||
|
QVBoxLayout *historyLayout = new QVBoxLayout(historyTab);
|
||||||
|
historyTextEdit = new QTextEdit();
|
||||||
|
historyTextEdit->setReadOnly(true);
|
||||||
|
historyTextEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
|
historyLayout->addWidget(historyTextEdit);
|
||||||
|
tabWidget->addTab(historyTab, "History");
|
||||||
|
|
||||||
|
QWidget *logTab = new QWidget;
|
||||||
|
QVBoxLayout *logLayout = new QVBoxLayout(logTab);
|
||||||
|
serverLogTextEdit = new QTextEdit();
|
||||||
|
serverLogTextEdit->setReadOnly(true);
|
||||||
|
logLayout->addWidget(serverLogTextEdit);
|
||||||
|
|
||||||
|
QGroupBox *customBox = new QGroupBox();
|
||||||
|
QHBoxLayout *customLayout = new QHBoxLayout(customBox);
|
||||||
|
customCommandEdit = new QLineEdit();
|
||||||
|
QPushButton *customButton = new QPushButton("Send Command");
|
||||||
|
connect(customButton, &QPushButton::clicked, this, &MainWindow::sendCustomCommand);
|
||||||
|
connect(customCommandEdit, &QLineEdit::returnPressed, this, &MainWindow::sendCustomCommand);
|
||||||
|
customLayout->addWidget(customCommandEdit);
|
||||||
|
customLayout->addWidget(customButton);
|
||||||
|
logLayout->addWidget(customBox);
|
||||||
|
|
||||||
|
tabWidget->addTab(logTab, "Console");
|
||||||
|
|
||||||
|
QWidget *connectionTab = new QWidget;
|
||||||
|
QVBoxLayout *connectionLayout = new QVBoxLayout(connectionTab);
|
||||||
|
|
||||||
QGroupBox *serverBox = new QGroupBox("Server Info");
|
QGroupBox *serverBox = new QGroupBox("Server Info");
|
||||||
QVBoxLayout *serverVBox = new QVBoxLayout(serverBox);
|
QVBoxLayout *serverVBox = new QVBoxLayout(serverBox);
|
||||||
QHBoxLayout *serverLayout = new QHBoxLayout();
|
QHBoxLayout *serverLayout = new QHBoxLayout();
|
||||||
@@ -151,71 +830,37 @@ void MainWindow::setupUI() {
|
|||||||
statusLayout->addWidget(connectButton);
|
statusLayout->addWidget(connectButton);
|
||||||
statusLayout->addWidget(disconnectButton);
|
statusLayout->addWidget(disconnectButton);
|
||||||
serverVBox->addLayout(statusLayout);
|
serverVBox->addLayout(statusLayout);
|
||||||
mainLayout->addWidget(serverBox);
|
connectionLayout->addWidget(serverBox);
|
||||||
|
|
||||||
QGroupBox *timeBox = new QGroupBox("Set Server Time");
|
QGroupBox *savedServersBox = new QGroupBox("Servers");
|
||||||
QHBoxLayout *timeLayout = new QHBoxLayout(timeBox);
|
QVBoxLayout *savedServersBoxLayout = new QVBoxLayout(savedServersBox);
|
||||||
dayEdit = new QLineEdit(); dayEdit->setMaxLength(2);
|
QHBoxLayout *savedServersLayout = new QHBoxLayout();
|
||||||
hourEdit = new QLineEdit(); hourEdit->setMaxLength(2);
|
savedServersCombo = new QComboBox();
|
||||||
minuteEdit = new QLineEdit(); minuteEdit->setMaxLength(2);
|
savedServersCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||||
QPushButton *timeButton = new QPushButton("Set Server Time");
|
QPushButton *saveServerButton = new QPushButton("Save");
|
||||||
connect(timeButton, &QPushButton::clicked, this, &MainWindow::sendTimeCommand);
|
QPushButton *loadServerButton = new QPushButton("Load");
|
||||||
timeLayout->addWidget(new QLabel("Day:"));
|
QPushButton *deleteServerButton = new QPushButton("Delete");
|
||||||
timeLayout->addWidget(dayEdit);
|
deleteServerButton->setStyleSheet("color: red;");
|
||||||
timeLayout->addWidget(new QLabel("Hour:"));
|
connect(saveServerButton, &QPushButton::clicked, this, &MainWindow::saveServerEntry);
|
||||||
timeLayout->addWidget(hourEdit);
|
connect(loadServerButton, &QPushButton::clicked, this, &MainWindow::loadSelectedServer);
|
||||||
timeLayout->addWidget(new QLabel("Minute:"));
|
connect(deleteServerButton, &QPushButton::clicked, this, &MainWindow::deleteSelectedServer);
|
||||||
timeLayout->addWidget(minuteEdit);
|
savedServersLayout->addWidget(savedServersCombo);
|
||||||
timeLayout->addStretch();
|
savedServersLayout->addWidget(saveServerButton);
|
||||||
timeLayout->addWidget(timeButton);
|
savedServersLayout->addWidget(loadServerButton);
|
||||||
mainLayout->addWidget(timeBox);
|
savedServersBoxLayout->addLayout(savedServersLayout);
|
||||||
|
savedServersBoxLayout->addWidget(deleteServerButton, 0, Qt::AlignHCenter);
|
||||||
|
connectionLayout->addWidget(savedServersBox);
|
||||||
|
connectionLayout->addStretch();
|
||||||
|
|
||||||
QGroupBox *speedBox = new QGroupBox("Set Game Speed");
|
tabWidget->addTab(connectionTab, "Connection");
|
||||||
QVBoxLayout *speedLayout = new QVBoxLayout(speedBox);
|
connect(tabWidget, &QTabWidget::currentChanged, this, [this, usersTab, bansTab](int index) {
|
||||||
QHBoxLayout *sliderLayout = new QHBoxLayout();
|
if (tabWidget->widget(index) == usersTab) {
|
||||||
speedSlider = new QSlider(Qt::Horizontal);
|
refreshUsers();
|
||||||
speedSlider->setMinimum(1);
|
} else if (tabWidget->widget(index) == bansTab) {
|
||||||
speedSlider->setMaximum(5);
|
refreshBans();
|
||||||
speedSlider->setTickInterval(1);
|
}
|
||||||
speedSlider->setTickPosition(QSlider::TicksBelow);
|
});
|
||||||
connect(speedSlider, &QSlider::valueChanged, this, &MainWindow::updateSliderLabel);
|
tabWidget->setCurrentWidget(connectionTab);
|
||||||
sliderLayout->addWidget(speedSlider);
|
|
||||||
QPushButton *speedButton = new QPushButton("Set Time Speed");
|
|
||||||
connect(speedButton, &QPushButton::clicked, this, &MainWindow::sendSpeedCommand);
|
|
||||||
sliderLayout->addWidget(speedButton);
|
|
||||||
sliderLabel = new QLabel("60");
|
|
||||||
sliderLabel->setAlignment(Qt::AlignCenter);
|
|
||||||
speedLayout->addLayout(sliderLayout);
|
|
||||||
speedLayout->addWidget(sliderLabel);
|
|
||||||
mainLayout->addWidget(speedBox);
|
|
||||||
|
|
||||||
tabWidget->addTab(mainTab, "Time");
|
|
||||||
|
|
||||||
QWidget *historyTab = new QWidget;
|
|
||||||
QVBoxLayout *historyLayout = new QVBoxLayout(historyTab);
|
|
||||||
historyTextEdit = new QTextEdit();
|
|
||||||
historyTextEdit->setReadOnly(true);
|
|
||||||
historyTextEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
|
||||||
historyLayout->addWidget(historyTextEdit);
|
|
||||||
tabWidget->addTab(historyTab, "History");
|
|
||||||
|
|
||||||
QWidget *logTab = new QWidget;
|
|
||||||
QVBoxLayout *logLayout = new QVBoxLayout(logTab);
|
|
||||||
serverLogTextEdit = new QTextEdit();
|
|
||||||
serverLogTextEdit->setReadOnly(true);
|
|
||||||
logLayout->addWidget(serverLogTextEdit);
|
|
||||||
|
|
||||||
QGroupBox *customBox = new QGroupBox();
|
|
||||||
QHBoxLayout *customLayout = new QHBoxLayout(customBox);
|
|
||||||
customCommandEdit = new QLineEdit();
|
|
||||||
QPushButton *customButton = new QPushButton("Send Command");
|
|
||||||
connect(customButton, &QPushButton::clicked, this, &MainWindow::sendCustomCommand);
|
|
||||||
connect(customCommandEdit, &QLineEdit::returnPressed, this, &MainWindow::sendCustomCommand);
|
|
||||||
customLayout->addWidget(customCommandEdit);
|
|
||||||
customLayout->addWidget(customButton);
|
|
||||||
logLayout->addWidget(customBox);
|
|
||||||
|
|
||||||
tabWidget->addTab(logTab, "Console");
|
|
||||||
|
|
||||||
updateSliderLabel(speedSlider->value());
|
updateSliderLabel(speedSlider->value());
|
||||||
}
|
}
|
||||||
|
|||||||
75
mainwindow.h
75
mainwindow.h
@@ -3,10 +3,13 @@
|
|||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
#include <QComboBox>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QMap>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
@@ -22,6 +25,19 @@ public:
|
|||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void saveServerEntry();
|
||||||
|
void loadSelectedServer();
|
||||||
|
void deleteSelectedServer();
|
||||||
|
void refreshUsers();
|
||||||
|
void displaySelectedUserInfo(int row);
|
||||||
|
void kickSelectedUser();
|
||||||
|
void banSelectedUser();
|
||||||
|
void refreshBans();
|
||||||
|
void displaySelectedBanInfo(int row);
|
||||||
|
void removeSelectedBan();
|
||||||
|
void lockServerTime();
|
||||||
|
void unlockServerTime();
|
||||||
|
void resendLockedServerTime();
|
||||||
void sendTimeCommand();
|
void sendTimeCommand();
|
||||||
void sendSpeedCommand();
|
void sendSpeedCommand();
|
||||||
void updateSliderLabel(int value);
|
void updateSliderLabel(int value);
|
||||||
@@ -32,22 +48,79 @@ private slots:
|
|||||||
void readServerOutput();
|
void readServerOutput();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct SavedServerEntry {
|
||||||
|
QString name;
|
||||||
|
QString server;
|
||||||
|
QString port;
|
||||||
|
QString password;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UserEntry {
|
||||||
|
QString playerId;
|
||||||
|
QString username;
|
||||||
|
QString position;
|
||||||
|
QString rotation;
|
||||||
|
QString remoteState;
|
||||||
|
QString health;
|
||||||
|
QString deaths;
|
||||||
|
QString zombies;
|
||||||
|
QString players;
|
||||||
|
QString score;
|
||||||
|
QString level;
|
||||||
|
QString platformId;
|
||||||
|
QString eosId;
|
||||||
|
QString ipAddress;
|
||||||
|
QString ping;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BanEntry {
|
||||||
|
QString bannedUntil;
|
||||||
|
QString userId;
|
||||||
|
QString username;
|
||||||
|
QString reason;
|
||||||
|
};
|
||||||
|
|
||||||
QLineEdit *serverEdit, *portEdit, *passwordEdit;
|
QLineEdit *serverEdit, *portEdit, *passwordEdit;
|
||||||
QLineEdit *dayEdit, *hourEdit, *minuteEdit;
|
QLineEdit *dayEdit, *hourEdit, *minuteEdit;
|
||||||
QLineEdit *customCommandEdit;
|
QLineEdit *customCommandEdit;
|
||||||
|
QComboBox *savedServersCombo;
|
||||||
|
QListWidget *usersListWidget;
|
||||||
|
QListWidget *bansListWidget;
|
||||||
|
QMap<QString, QLabel *> userInfoValueLabels;
|
||||||
|
QMap<QString, QLabel *> banInfoValueLabels;
|
||||||
QSlider *speedSlider;
|
QSlider *speedSlider;
|
||||||
QLabel *sliderLabel;
|
QLabel *sliderLabel;
|
||||||
QLabel *connectionStatusLabel;
|
QLabel *connectionStatusLabel;
|
||||||
|
QLabel *serverTimeStatusLabel;
|
||||||
|
QPushButton *serverTimeLockButton;
|
||||||
QTcpSocket *socket;
|
QTcpSocket *socket;
|
||||||
QPushButton *connectButton;
|
QPushButton *connectButton;
|
||||||
QPushButton *disconnectButton;
|
QPushButton *disconnectButton;
|
||||||
QTimer *statusTimer;
|
QTimer *statusTimer;
|
||||||
|
QTimer *lockedTimeTimer;
|
||||||
QTextEdit *historyTextEdit;
|
QTextEdit *historyTextEdit;
|
||||||
QTextEdit *serverLogTextEdit;
|
QTextEdit *serverLogTextEdit;
|
||||||
QTabWidget *tabWidget;
|
QTabWidget *tabWidget;
|
||||||
|
QList<SavedServerEntry> savedServers;
|
||||||
|
QList<UserEntry> users;
|
||||||
|
QList<BanEntry> bans;
|
||||||
bool isAuthenticated = false;
|
bool isAuthenticated = false;
|
||||||
|
bool isServerTimeLocked = false;
|
||||||
|
bool awaitingUsersResponse = false;
|
||||||
|
bool awaitingBansResponse = false;
|
||||||
|
QString usersResponseBuffer;
|
||||||
|
QString bansResponseBuffer;
|
||||||
|
|
||||||
void sendTelnetCommand(const QString &command);
|
QString serverConfigFilePath() const;
|
||||||
|
void clearUserInfo();
|
||||||
|
void clearBanInfo();
|
||||||
|
void loadSavedServers();
|
||||||
|
void parseUsersResponse(const QString &text);
|
||||||
|
void parseBansResponse(const QString &text);
|
||||||
|
bool writeSavedServers() const;
|
||||||
|
bool sendValidatedTimeCommand();
|
||||||
|
void updateServerTimeLockState(bool locked);
|
||||||
|
bool sendTelnetCommand(const QString &command);
|
||||||
void setupUI();
|
void setupUI();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user