685 lines
22 KiB
C++
685 lines
22 KiB
C++
#include "mainwindow.h"
|
|
#include "ui_mainwindow.h"
|
|
|
|
#include <QMessageBox>
|
|
#include <QRandomGenerator>
|
|
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
: QMainWindow(parent)
|
|
, ui(new Ui::MainWindow)
|
|
, mSteamPath()
|
|
{
|
|
ui->setupUi(this);
|
|
// Don't load maps here - call initializeAsync() after showing splash screen
|
|
}
|
|
|
|
void MainWindow::initializeAsync()
|
|
{
|
|
emit loadingProgress(5, "Finding Steam installation...");
|
|
QCoreApplication::processEvents();
|
|
|
|
findSteamPath();
|
|
|
|
emit loadingProgress(10, "Scanning workshop directory...");
|
|
QCoreApplication::processEvents();
|
|
|
|
QDir gwfWorkshopDir(mSteamPath + "/steamapps/workshop/content/431240");
|
|
if (!gwfWorkshopDir.exists())
|
|
{
|
|
emit loadingProgress(100, "Ready (no maps found)");
|
|
emit loadingComplete();
|
|
return;
|
|
}
|
|
|
|
qDebug() << "Found Golf With Friends Workshop Path:" << gwfWorkshopDir.path();
|
|
|
|
QStringList entries = gwfWorkshopDir.entryList({}, QDir::NoDotAndDotDot | QDir::Dirs, QDir::Time);
|
|
int totalEntries = entries.size();
|
|
int processed = 0;
|
|
|
|
foreach (const QString entry, entries)
|
|
{
|
|
// Calculate and emit progress (10-90%)
|
|
int progress = 10 + (processed * 80 / qMax(totalEntries, 1));
|
|
emit loadingProgress(progress, QString("Loading map: %1").arg(entry));
|
|
QCoreApplication::processEvents();
|
|
|
|
QFile newEntry(gwfWorkshopDir.path() + "/" + entry + "/Map");
|
|
if (!newEntry.open(QIODevice::ReadWrite))
|
|
{
|
|
qDebug() << "Failed to open workshop map:" << entry;
|
|
processed++;
|
|
continue;
|
|
}
|
|
const QByteArray rawMapData = newEntry.readAll();
|
|
|
|
size_t headerSize = rawMapData.indexOf('{');
|
|
size_t footerSize = rawMapData.size() - rawMapData.lastIndexOf('}') - 1;
|
|
size_t payloadSize = rawMapData.size() - headerSize - footerSize;
|
|
|
|
const QByteArray mapData = rawMapData.mid(headerSize, payloadSize);
|
|
|
|
QJsonDocument loadDoc = QJsonDocument::fromJson(mapData);
|
|
QJsonObject loadObj = loadDoc.object();
|
|
|
|
LevelInfo newInfo;
|
|
newInfo.mLevelName = loadObj["levelName"].toString() + QString(" [%1]").arg(entry);
|
|
newInfo.mDescription = loadObj["description"].toString();
|
|
newInfo.mPublishedID = QString::number(loadObj["publishedID"].toInt());
|
|
newInfo.mMusic = loadObj["music"].toInt();
|
|
newInfo.mSkybox = loadObj["skybox"].toInt();
|
|
newInfo.mPreview = QPixmap(gwfWorkshopDir.path() + "/" + entry + "/Preview.jpg");
|
|
newInfo.mPowerUps = findPowerUps(loadObj);
|
|
newInfo.mMaxViewID = getMaxViewID(loadObj);
|
|
newInfo.mObjectPositions = getObjectPositions(loadObj);
|
|
newInfo.mMapPath = newEntry.fileName();
|
|
newInfo.mMapData = loadObj;
|
|
|
|
mLevels.push_back(newInfo);
|
|
processed++;
|
|
}
|
|
|
|
emit loadingProgress(95, "Updating level list...");
|
|
QCoreApplication::processEvents();
|
|
|
|
updateLevels();
|
|
|
|
emit loadingProgress(100, "Ready!");
|
|
emit loadingComplete();
|
|
}
|
|
|
|
void MainWindow::findSteamPath()
|
|
{
|
|
// Check multiple common Steam installation locations
|
|
QStringList possiblePaths = {
|
|
"C:/Program Files (x86)/Steam",
|
|
"C:/Program Files/Steam",
|
|
"D:/Steam",
|
|
"D:/Games/Steam",
|
|
"E:/Steam",
|
|
"E:/Games/Steam"
|
|
};
|
|
|
|
for (const QString &path : possiblePaths)
|
|
{
|
|
QDir testDir(path);
|
|
if (testDir.exists())
|
|
{
|
|
mSteamPath = testDir.path();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If not found in common locations, ask user
|
|
if (mSteamPath.isEmpty())
|
|
{
|
|
mSteamPath = QFileDialog::getExistingDirectory(this, "Select Steam Directory",
|
|
"C:/Program Files (x86)/", QFileDialog::ShowDirsOnly);
|
|
}
|
|
|
|
if (!mSteamPath.isEmpty())
|
|
{
|
|
// Verify the GWF workshop folder exists
|
|
QDir gwfDir(mSteamPath + "/steamapps/workshop/content/431240");
|
|
if (!gwfDir.exists())
|
|
{
|
|
ui->lineEdit_SteamPath->setText(QString("FOUND: %1 (No GWF maps)").arg(mSteamPath));
|
|
}
|
|
else
|
|
{
|
|
ui->lineEdit_SteamPath->setText(QString("FOUND: %1").arg(mSteamPath));
|
|
}
|
|
ui->lineEdit_SteamPath->setEnabled(false);
|
|
}
|
|
else
|
|
{
|
|
ui->lineEdit_SteamPath->setText("NOT FOUND - Please install Steam or GWF workshop maps");
|
|
}
|
|
}
|
|
|
|
void MainWindow::updateLevels()
|
|
{
|
|
ui->listWidget_MapSelect->clear();
|
|
for (int i = 0; i < mLevels.size(); i++)
|
|
{
|
|
ui->listWidget_MapSelect->addItem(mLevels[i].mLevelName);
|
|
}
|
|
}
|
|
|
|
QVector<QVector3D> MainWindow::getObjectPositions(QJsonObject aMapData)
|
|
{
|
|
QVector<QVector3D> result;
|
|
QJsonArray objData = aMapData["editorObjectData"].toArray();
|
|
|
|
for (int i = 0; i < objData.size(); i++)
|
|
{
|
|
QJsonObject currentObject = objData[i].toObject();
|
|
|
|
if (currentObject["obName"].toString().contains("base", Qt::CaseInsensitive))
|
|
{
|
|
QVector3D position;
|
|
position.setX(currentObject["pX"].toDouble());
|
|
position.setY(currentObject["pY"].toDouble());
|
|
position.setZ(currentObject["pZ"].toDouble());
|
|
result.push_back(position);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int MainWindow::getMaxViewID(QJsonObject aMapData)
|
|
{
|
|
QVector<QVector3D> result;
|
|
QJsonArray objData = aMapData["editorObjectData"].toArray();
|
|
int maxViewID = 0;
|
|
|
|
for (int i = 0; i < objData.size(); i++)
|
|
{
|
|
QJsonObject currentObject = objData[i].toObject();
|
|
|
|
QJsonArray viewIDs = currentObject["photonData"].toObject()["photonViewID"].toArray();
|
|
|
|
if (viewIDs.isEmpty()) { continue; }
|
|
|
|
maxViewID = fmax(viewIDs.first().toInt(), maxViewID);
|
|
}
|
|
return maxViewID;
|
|
}
|
|
|
|
QVector<PowerUpInfo> MainWindow::findPowerUps(QJsonObject aMapData)
|
|
{
|
|
QVector<PowerUpInfo> result;
|
|
QJsonArray objData = aMapData["editorObjectData"].toArray();
|
|
|
|
for (int i = 0; i < objData.size(); i++)
|
|
{
|
|
QJsonObject currentObject = objData[i].toObject();
|
|
const QString objName = currentObject["obName"].toString();
|
|
if (objName == "Powerup Spawner")
|
|
{
|
|
PowerUpInfo newPowerUp;
|
|
newPowerUp.mPosition.setX(currentObject["pX"].toDouble());
|
|
newPowerUp.mPosition.setY(currentObject["pY"].toDouble());
|
|
newPowerUp.mPosition.setZ(currentObject["pZ"].toDouble());
|
|
|
|
newPowerUp.mRotation.setW(currentObject["rW"].toDouble());
|
|
newPowerUp.mRotation.setX(currentObject["rX"].toDouble());
|
|
newPowerUp.mRotation.setY(currentObject["rY"].toDouble());
|
|
newPowerUp.mRotation.setZ(currentObject["rZ"].toDouble());
|
|
|
|
newPowerUp.mScale.setX(currentObject["sX"].toDouble());
|
|
newPowerUp.mScale.setY(currentObject["sY"].toDouble());
|
|
newPowerUp.mScale.setZ(currentObject["sZ"].toDouble());
|
|
result.push_back(newPowerUp);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
void MainWindow::on_listWidget_MapSelect_currentRowChanged(int currentRow)
|
|
{
|
|
// Bounds checking to prevent crashes
|
|
if (currentRow < 0 || currentRow >= mLevels.size())
|
|
{
|
|
clearMapDetails();
|
|
return;
|
|
}
|
|
|
|
const LevelInfo &selectedLevel = mLevels[currentRow];
|
|
ui->lineEdit_LevelName->setText(selectedLevel.mLevelName);
|
|
ui->lineEdit_Description->setText(selectedLevel.mDescription);
|
|
ui->lineEdit_ID->setText(selectedLevel.mPublishedID);
|
|
ui->spinBox_Music->setValue(selectedLevel.mMusic);
|
|
ui->spinBox_Skybox->setValue(selectedLevel.mSkybox);
|
|
ui->spinBox_PowerupCount->setValue(selectedLevel.mPowerUps.size());
|
|
|
|
QPixmap scaledPreview = selectedLevel.mPreview.scaled(ui->label_MapPreview->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
ui->label_MapPreview->setPixmap(scaledPreview);
|
|
|
|
// Clear the powerup list before adding new items (fixes accumulation bug)
|
|
ui->listWidget_powerups->clear();
|
|
|
|
for (int i = 0; i < selectedLevel.mPowerUps.size(); i++)
|
|
{
|
|
ui->listWidget_powerups->addItem(QString("Powerup %1").arg(i));
|
|
}
|
|
}
|
|
|
|
|
|
void MainWindow::on_listWidget_powerups_currentRowChanged(int currentRow)
|
|
{
|
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
|
|
|
// Bounds checking for map selection
|
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
|
{
|
|
clearPowerupDetails();
|
|
return;
|
|
}
|
|
|
|
const LevelInfo &selectedLevel = mLevels[mapRow];
|
|
|
|
// Bounds checking for powerup selection
|
|
if (currentRow < 0 || currentRow >= selectedLevel.mPowerUps.size())
|
|
{
|
|
clearPowerupDetails();
|
|
return;
|
|
}
|
|
|
|
const PowerUpInfo &selectedPowerUp = selectedLevel.mPowerUps[currentRow];
|
|
|
|
ui->doubleSpinBox_PosX->setValue(selectedPowerUp.mPosition.x());
|
|
ui->doubleSpinBox_PosY->setValue(selectedPowerUp.mPosition.y());
|
|
ui->doubleSpinBox_PosZ->setValue(selectedPowerUp.mPosition.z());
|
|
|
|
ui->doubleSpinBox_RotW->setValue(selectedPowerUp.mRotation.w());
|
|
ui->doubleSpinBox_RotX->setValue(selectedPowerUp.mRotation.x());
|
|
ui->doubleSpinBox_RotY->setValue(selectedPowerUp.mRotation.y());
|
|
ui->doubleSpinBox_RotZ->setValue(selectedPowerUp.mRotation.z());
|
|
|
|
ui->doubleSpinBox_ScaleX->setValue(selectedPowerUp.mScale.x());
|
|
ui->doubleSpinBox_ScaleY->setValue(selectedPowerUp.mScale.y());
|
|
ui->doubleSpinBox_ScaleZ->setValue(selectedPowerUp.mScale.z());
|
|
}
|
|
|
|
void MainWindow::saveMap(LevelInfo aLevelInfo, bool aBackup)
|
|
{
|
|
const QString mapPath = aLevelInfo.mMapPath;
|
|
if (!QFile::exists(mapPath))
|
|
{
|
|
QMessageBox::critical(this, "Save Error",
|
|
QString("Map file not found:\n%1").arg(mapPath));
|
|
return;
|
|
}
|
|
|
|
const QString backupMapPath = aLevelInfo.mMapPath + ".old";
|
|
if (!QFile::exists(backupMapPath) && aBackup)
|
|
{
|
|
if (!QFile::copy(mapPath, backupMapPath))
|
|
{
|
|
QMessageBox::warning(this, "Backup Warning",
|
|
"Could not create backup file. Proceeding without backup.");
|
|
}
|
|
}
|
|
|
|
QFile backupMapFile(backupMapPath);
|
|
if (!backupMapFile.open(QIODevice::ReadOnly))
|
|
{
|
|
QMessageBox::critical(this, "Save Error",
|
|
QString("Failed to open backup file for reading:\n%1").arg(backupMapPath));
|
|
return;
|
|
}
|
|
|
|
const QByteArray backupData = backupMapFile.readAll().simplified();
|
|
backupMapFile.close();
|
|
|
|
QFile mapFile(mapPath);
|
|
if (!mapFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
|
{
|
|
QMessageBox::critical(this, "Save Error",
|
|
QString("Failed to open map file for writing:\n%1").arg(mapPath));
|
|
return;
|
|
}
|
|
|
|
QByteArray powerUpsData = ",";
|
|
|
|
for (int i = 0; i < aLevelInfo.mPowerUps.size(); i++)
|
|
{
|
|
const PowerUpInfo &powerUp = aLevelInfo.mPowerUps[i];
|
|
const QString powerUpData = QString("{\"sType\":%1,\"pX\":%2,\"pY\":%3,\"pZ\":%4,\"rW\":%5,\"rX\":%6,\"rY\":%7,\"rZ\":%8,\"sX\":%9,\"sY\":%10,\"sZ\":%11,\"obName\":\"Powerup Spawner\",\"photonData\":{\"photonViewID\":[%12]}},")
|
|
.arg(0)
|
|
.arg(powerUp.mPosition.x(), 0, 'f', 1)
|
|
.arg(powerUp.mPosition.y(), 0, 'f', 1)
|
|
.arg(powerUp.mPosition.z(), 0, 'f', 1)
|
|
.arg(powerUp.mRotation.w(), 0, 'f', 1)
|
|
.arg(powerUp.mRotation.x(), 0, 'f', 1)
|
|
.arg(powerUp.mRotation.y(), 0, 'f', 1)
|
|
.arg(powerUp.mRotation.z(), 0, 'f', 1)
|
|
.arg(powerUp.mScale.x(), 0, 'f', 1)
|
|
.arg(powerUp.mScale.y(), 0, 'f', 1)
|
|
.arg(powerUp.mScale.z(), 0, 'f', 1)
|
|
.arg(i + 4 + aLevelInfo.mMaxViewID);
|
|
powerUpsData.append(powerUpData.toUtf8());
|
|
}
|
|
powerUpsData = powerUpsData.mid(0, powerUpsData.size() - 1);
|
|
|
|
int injectionPoint = backupData.lastIndexOf(']');
|
|
|
|
QByteArray mapData;
|
|
mapData.append(backupData.mid(0, injectionPoint));
|
|
mapData.append(powerUpsData);
|
|
mapData.append(backupData.mid(injectionPoint));
|
|
|
|
if (mapFile.write(mapData) == -1)
|
|
{
|
|
QMessageBox::critical(this, "Save Error",
|
|
QString("Failed to write map data:\n%1").arg(mapPath));
|
|
mapFile.close();
|
|
return;
|
|
}
|
|
|
|
mapFile.close();
|
|
qDebug() << "Map saved successfully:" << mapPath;
|
|
}
|
|
|
|
void MainWindow::on_pushButton_Generate_clicked()
|
|
{
|
|
int currentListRow = ui->listWidget_MapSelect->currentRow();
|
|
|
|
// Bounds check
|
|
if (currentListRow < 0 || currentListRow >= mLevels.size())
|
|
{
|
|
QMessageBox::warning(this, "No Map Selected",
|
|
"Please select a map before generating powerups.");
|
|
return;
|
|
}
|
|
|
|
LevelInfo selectedLevel = mLevels[currentListRow];
|
|
|
|
// Check if powerups already exist and ask user what to do
|
|
if (!selectedLevel.mPowerUps.isEmpty())
|
|
{
|
|
QMessageBox::StandardButton reply = QMessageBox::question(this,
|
|
"Existing Powerups Found",
|
|
QString("This map already has %1 powerup(s).\n\n"
|
|
"Do you want to replace them with new generated powerups?\n\n"
|
|
"Click 'Yes' to replace, 'No' to add to existing, or 'Cancel' to abort.")
|
|
.arg(selectedLevel.mPowerUps.size()),
|
|
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
|
|
QMessageBox::Cancel);
|
|
|
|
if (reply == QMessageBox::Cancel)
|
|
{
|
|
return;
|
|
}
|
|
if (reply == QMessageBox::Yes)
|
|
{
|
|
selectedLevel.mPowerUps.clear();
|
|
}
|
|
// If No, keep existing and add new ones
|
|
}
|
|
|
|
QVector<QVector3D> shuffledPositions = selectedLevel.mObjectPositions;
|
|
|
|
if (shuffledPositions.isEmpty())
|
|
{
|
|
QMessageBox::warning(this, "No Base Objects",
|
|
"This map has no base objects to use as spawn positions.\n"
|
|
"Powerups are generated near objects with 'base' in their name.");
|
|
return;
|
|
}
|
|
|
|
auto rng = QRandomGenerator::global();
|
|
std::shuffle(shuffledPositions.begin(), shuffledPositions.end(), *rng);
|
|
|
|
int generatedCount = 0;
|
|
for (int i = 0; i < shuffledPositions.size(); i++)
|
|
{
|
|
if (i == MAX_POWERUPS)
|
|
{
|
|
break;
|
|
}
|
|
if ((rand() % 100) < 75)
|
|
{
|
|
QVector3D pos = shuffledPositions[i];
|
|
|
|
int sign = 1;
|
|
if ((rand() % 100) < 50)
|
|
{
|
|
sign = -1;
|
|
}
|
|
|
|
pos.setX(pos.x() + sign * (rand() % 2));
|
|
pos.setY(pos.y() + sign * (rand() % 2));
|
|
|
|
PowerUpInfo newPowerUp;
|
|
newPowerUp.mPosition = QVector3D(pos.x(), pos.y() + 0.25, pos.z());
|
|
newPowerUp.mRotation = QVector4D(0, 0, 0, 1); // Identity quaternion
|
|
newPowerUp.mScale = QVector3D(1, 1, 1);
|
|
selectedLevel.mPowerUps.push_back(newPowerUp);
|
|
generatedCount++;
|
|
}
|
|
}
|
|
|
|
saveMap(selectedLevel, true);
|
|
|
|
mLevels[currentListRow] = selectedLevel;
|
|
|
|
// Refresh the UI to show the new powerups
|
|
ui->listWidget_MapSelect->setCurrentRow(-1); // Deselect first
|
|
ui->listWidget_MapSelect->setCurrentRow(currentListRow); // Reselect to refresh
|
|
|
|
ui->statusBar->showMessage(QString("Generated %1 powerups successfully!").arg(generatedCount), 5000);
|
|
}
|
|
|
|
void MainWindow::clearMapDetails()
|
|
{
|
|
ui->lineEdit_LevelName->clear();
|
|
ui->lineEdit_Description->clear();
|
|
ui->lineEdit_ID->clear();
|
|
ui->spinBox_Music->setValue(0);
|
|
ui->spinBox_Skybox->setValue(0);
|
|
ui->spinBox_PowerupCount->setValue(0);
|
|
ui->label_MapPreview->clear();
|
|
ui->listWidget_powerups->clear();
|
|
clearPowerupDetails();
|
|
}
|
|
|
|
void MainWindow::clearPowerupDetails()
|
|
{
|
|
ui->doubleSpinBox_PosX->setValue(0);
|
|
ui->doubleSpinBox_PosY->setValue(0);
|
|
ui->doubleSpinBox_PosZ->setValue(0);
|
|
ui->doubleSpinBox_RotW->setValue(0);
|
|
ui->doubleSpinBox_RotX->setValue(0);
|
|
ui->doubleSpinBox_RotY->setValue(0);
|
|
ui->doubleSpinBox_RotZ->setValue(0);
|
|
ui->doubleSpinBox_ScaleX->setValue(0);
|
|
ui->doubleSpinBox_ScaleY->setValue(0);
|
|
ui->doubleSpinBox_ScaleZ->setValue(0);
|
|
}
|
|
|
|
void MainWindow::refreshPowerupList(int mapRow)
|
|
{
|
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
|
{
|
|
ui->listWidget_powerups->clear();
|
|
return;
|
|
}
|
|
|
|
ui->listWidget_powerups->clear();
|
|
const LevelInfo &level = mLevels[mapRow];
|
|
for (int i = 0; i < level.mPowerUps.size(); i++)
|
|
{
|
|
ui->listWidget_powerups->addItem(QString("Powerup %1").arg(i));
|
|
}
|
|
ui->spinBox_PowerupCount->setValue(level.mPowerUps.size());
|
|
}
|
|
|
|
void MainWindow::on_pushButton_SavePowerUp_clicked()
|
|
{
|
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
|
int powerupRow = ui->listWidget_powerups->currentRow();
|
|
|
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
|
{
|
|
QMessageBox::warning(this, "No Map Selected",
|
|
"Please select a map first.");
|
|
return;
|
|
}
|
|
|
|
if (powerupRow < 0 || powerupRow >= mLevels[mapRow].mPowerUps.size())
|
|
{
|
|
QMessageBox::warning(this, "No Powerup Selected",
|
|
"Please select a powerup to save.");
|
|
return;
|
|
}
|
|
|
|
// Read values from UI and update the powerup
|
|
PowerUpInfo &powerup = mLevels[mapRow].mPowerUps[powerupRow];
|
|
powerup.mPosition.setX(ui->doubleSpinBox_PosX->value());
|
|
powerup.mPosition.setY(ui->doubleSpinBox_PosY->value());
|
|
powerup.mPosition.setZ(ui->doubleSpinBox_PosZ->value());
|
|
powerup.mRotation.setW(ui->doubleSpinBox_RotW->value());
|
|
powerup.mRotation.setX(ui->doubleSpinBox_RotX->value());
|
|
powerup.mRotation.setY(ui->doubleSpinBox_RotY->value());
|
|
powerup.mRotation.setZ(ui->doubleSpinBox_RotZ->value());
|
|
powerup.mScale.setX(ui->doubleSpinBox_ScaleX->value());
|
|
powerup.mScale.setY(ui->doubleSpinBox_ScaleY->value());
|
|
powerup.mScale.setZ(ui->doubleSpinBox_ScaleZ->value());
|
|
|
|
// Save to disk
|
|
saveMap(mLevels[mapRow], true);
|
|
|
|
ui->statusBar->showMessage("Powerup saved successfully!", 3000);
|
|
}
|
|
|
|
void MainWindow::on_pushButton_NewPowerUp_clicked()
|
|
{
|
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
|
|
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
|
{
|
|
QMessageBox::warning(this, "No Map Selected",
|
|
"Please select a map before adding a powerup.");
|
|
return;
|
|
}
|
|
|
|
// Create new powerup at origin with default values
|
|
PowerUpInfo newPowerup;
|
|
newPowerup.mPosition = QVector3D(0, 0.25, 0);
|
|
newPowerup.mRotation = QVector4D(0, 0, 0, 1); // Identity quaternion
|
|
newPowerup.mScale = QVector3D(1, 1, 1);
|
|
|
|
mLevels[mapRow].mPowerUps.append(newPowerup);
|
|
|
|
// Refresh the powerup list
|
|
refreshPowerupList(mapRow);
|
|
|
|
// Select the new powerup
|
|
ui->listWidget_powerups->setCurrentRow(mLevels[mapRow].mPowerUps.size() - 1);
|
|
|
|
ui->statusBar->showMessage("New powerup added. Edit values and click Save.", 3000);
|
|
}
|
|
|
|
void MainWindow::on_pushButton_DeletePowerUp_clicked()
|
|
{
|
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
|
int powerupRow = ui->listWidget_powerups->currentRow();
|
|
|
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
|
{
|
|
QMessageBox::warning(this, "No Map Selected",
|
|
"Please select a map first.");
|
|
return;
|
|
}
|
|
|
|
if (powerupRow < 0 || powerupRow >= mLevels[mapRow].mPowerUps.size())
|
|
{
|
|
QMessageBox::warning(this, "No Powerup Selected",
|
|
"Please select a powerup to delete.");
|
|
return;
|
|
}
|
|
|
|
QMessageBox::StandardButton reply = QMessageBox::question(this,
|
|
"Confirm Delete",
|
|
QString("Are you sure you want to delete Powerup %1?").arg(powerupRow),
|
|
QMessageBox::Yes | QMessageBox::No,
|
|
QMessageBox::No);
|
|
|
|
if (reply == QMessageBox::Yes)
|
|
{
|
|
mLevels[mapRow].mPowerUps.remove(powerupRow);
|
|
|
|
// Save to disk
|
|
saveMap(mLevels[mapRow], true);
|
|
|
|
// Refresh powerup list
|
|
refreshPowerupList(mapRow);
|
|
clearPowerupDetails();
|
|
|
|
ui->statusBar->showMessage("Powerup deleted successfully!", 3000);
|
|
}
|
|
}
|
|
|
|
void MainWindow::on_pushButton_Restore_clicked()
|
|
{
|
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
|
|
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
|
{
|
|
QMessageBox::warning(this, "No Map Selected",
|
|
"Please select a map to restore.");
|
|
return;
|
|
}
|
|
|
|
QString backupPath = mLevels[mapRow].mMapPath + ".old";
|
|
if (!QFile::exists(backupPath))
|
|
{
|
|
QMessageBox::information(this, "No Backup",
|
|
"No backup file exists for this map.\n"
|
|
"Backups are created automatically when you generate or modify powerups.");
|
|
return;
|
|
}
|
|
|
|
QMessageBox::StandardButton reply = QMessageBox::question(this,
|
|
"Restore Backup",
|
|
"This will restore the map to its original state before any modifications.\n\n"
|
|
"All powerup changes will be lost. Are you sure you want to continue?",
|
|
QMessageBox::Yes | QMessageBox::No,
|
|
QMessageBox::No);
|
|
|
|
if (reply == QMessageBox::Yes)
|
|
{
|
|
QString mapPath = mLevels[mapRow].mMapPath;
|
|
|
|
// Remove current map file
|
|
if (!QFile::remove(mapPath))
|
|
{
|
|
QMessageBox::critical(this, "Restore Error",
|
|
"Failed to remove current map file.");
|
|
return;
|
|
}
|
|
|
|
// Copy backup to map file
|
|
if (!QFile::copy(backupPath, mapPath))
|
|
{
|
|
QMessageBox::critical(this, "Restore Error",
|
|
"Failed to restore backup file.");
|
|
return;
|
|
}
|
|
|
|
// Reload the map data
|
|
QFile mapFile(mapPath);
|
|
if (mapFile.open(QIODevice::ReadOnly))
|
|
{
|
|
const QByteArray rawMapData = mapFile.readAll();
|
|
size_t headerSize = rawMapData.indexOf('{');
|
|
size_t footerSize = rawMapData.size() - rawMapData.lastIndexOf('}') - 1;
|
|
size_t payloadSize = rawMapData.size() - headerSize - footerSize;
|
|
const QByteArray mapData = rawMapData.mid(headerSize, payloadSize);
|
|
|
|
QJsonDocument loadDoc = QJsonDocument::fromJson(mapData);
|
|
QJsonObject loadObj = loadDoc.object();
|
|
|
|
mLevels[mapRow].mPowerUps = findPowerUps(loadObj);
|
|
mLevels[mapRow].mMaxViewID = getMaxViewID(loadObj);
|
|
mLevels[mapRow].mMapData = loadObj;
|
|
|
|
mapFile.close();
|
|
}
|
|
|
|
// Refresh UI
|
|
refreshPowerupList(mapRow);
|
|
clearPowerupDetails();
|
|
|
|
ui->statusBar->showMessage("Map restored from backup successfully!", 3000);
|
|
}
|
|
}
|
|
|