Compare commits

...

2 Commits

Author SHA1 Message Date
njohnson
b09f8a85e0 Initial commit. 2025-12-16 15:03:30 -05:00
njohnson
76d3e2927f Add .gitignore. 2025-12-16 15:03:19 -05:00
6 changed files with 1106 additions and 0 deletions

82
.gitignore vendored Normal file
View File

@ -0,0 +1,82 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
*.qbs.user*
CMakeLists.txt.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe
# Directories with generated files
.moc/
.obj/
.pch/
.rcc/
.uic/
/build*/

22
GWF_PowerupInjector.pro Normal file
View File

@ -0,0 +1,22 @@
QT += core gui widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

11
main.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

308
mainwindow.cpp Normal file
View File

@ -0,0 +1,308 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QRandomGenerator>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, mSteamPath()
{
ui->setupUi(this);
findSteamPath();
QDir gwfWorkshopDir(mSteamPath + "/steamapps/workshop/content/431240");
if (!gwfWorkshopDir.exists()) { return; }
qDebug() << "Found Golf With Friends Workshop Path:" << gwfWorkshopDir.path();
foreach (const QString entry, gwfWorkshopDir.entryList({}, QDir::NoFilter, QDir::Time))
{
if (entry == "." || entry == "..") { continue; }
QFile newEntry(gwfWorkshopDir.path() + "/" + entry + "/Map");
if (!newEntry.open(QIODevice::ReadWrite))
{
qDebug() << "Failed to open workshop map:" << entry;
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);
}
updateLevels();
}
void MainWindow::findSteamPath()
{
QDir testDir("C:/Program Files (x86)/Steam");
if (testDir.exists())
{
mSteamPath = testDir.path();
}
else
{
mSteamPath = QFileDialog::getExistingDirectory(this, "Select Steam Directory", "C:/Program Files (x86)/", QFileDialog::ShowDirsOnly);
}
if (!mSteamPath.isEmpty())
{
ui->lineEdit_SteamPath->setText(QString("FOUND: %1").arg(mSteamPath));
ui->lineEdit_SteamPath->setEnabled(false);
}
}
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)
{
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);
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)
{
LevelInfo selectedLevel = mLevels[ui->listWidget_MapSelect->currentRow()];
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))
{
qDebug() << "File doesn't exist: " << mapPath;
return;
}
const QString backupMapPath = aLevelInfo.mMapPath + ".old";
if (!QFile::exists(backupMapPath) && aBackup)
{
QFile::copy(mapPath, backupMapPath);
}
QFile backupMapFile(backupMapPath);
if (!backupMapFile.open(QIODevice::ReadOnly))
{
qDebug() << "Failed to open backup file: " << mapPath;
return;
}
const QByteArray backupData = backupMapFile.readAll().simplified();
backupMapFile.close();
QFile mapFile(mapPath);
if (!mapFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
{
qDebug() << "Failed to open file: " << mapPath;
return;
}
QByteArray powerUpsData = ",";
for (int i = 0; i < aLevelInfo.mPowerUps.size(); i++)
{
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));
mapFile.write(mapData);
mapFile.close();
}
void MainWindow::on_pushButton_Generate_clicked()
{
int currentListRow = ui->listWidget_MapSelect->currentRow();
LevelInfo selectedLevel = mLevels[currentListRow];
QVector<QVector3D> shuffledPositions = selectedLevel.mObjectPositions;
auto rng = QRandomGenerator::global();
std::shuffle(shuffledPositions.begin(), shuffledPositions.end(), *rng);
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.mScale = QVector3D(1, 1, 1);
selectedLevel.mPowerUps.push_back(newPowerUp);
}
}
saveMap(selectedLevel, true);
mLevels[ui->listWidget_MapSelect->currentRow()] = selectedLevel;
ui->listWidget_MapSelect->setCurrentRow(currentListRow);
}

78
mainwindow.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QString>
#include <QVector>
#include <QDir>
#include <QFileDialog>
#include <QVector3D>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonValue>
#include <QJsonObject>
struct PowerUpInfo
{
QVector3D mPosition;
QVector4D mRotation;
QVector3D mScale;
};
struct LevelInfo
{
QString mLevelName;
QString mDescription;
QString mPublishedID;
int mMusic;
int mSkybox;
QPixmap mPreview;
QVector<PowerUpInfo> mPowerUps;
int mMaxViewID;
QVector<QVector3D> mObjectPositions;
QString mMapPath;
QJsonObject mMapData;
};
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
#define MAX_POWERUPS 100
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void findSteamPath();
void updateLevels();
QVector<PowerUpInfo> findPowerUps(QJsonObject aMapData);
QVector<QVector3D> getObjectPositions(QJsonObject aObj);
void saveMap(LevelInfo aLevelInfo, bool aBackup = true);
QByteArray serializePowerUpCompact(const PowerUpInfo &p, int photonId);
int getMaxViewID(QJsonObject aMapData);
private slots:
void on_listWidget_MapSelect_currentRowChanged(int currentRow);
void on_listWidget_powerups_currentRowChanged(int currentRow);
void on_pushButton_Generate_clicked();
private:
Ui::MainWindow *ui;
QString mSteamPath;
QVector<LevelInfo> mLevels;
};
#endif // MAINWINDOW_H

605
mainwindow.ui Normal file
View File

@ -0,0 +1,605 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1330</width>
<height>585</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>1231</width>
<height>580</height>
</size>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Steam Path:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_SteamPath">
<property name="placeholderText">
<string>NOT FOUND</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QListWidget" name="listWidget_MapSelect">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Map Details</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Level Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_LevelName">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="placeholderText">
<string>Select a level</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Description:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_Description">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="placeholderText">
<string>Select a level</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Published ID:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_ID">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="placeholderText">
<string>Select a level</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_MapPreview">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Music:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_Music"/>
</item>
<item>
<widget class="QComboBox" name="comboBox"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Skybox:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_Skybox"/>
</item>
<item>
<widget class="QComboBox" name="comboBox_2"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QLabel" name="label_18">
<property name="text">
<string>Powerup Count:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_PowerupCount">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_Powerups">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Powerup Details</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QListWidget" name="listWidget_powerups">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_PosX">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="1" column="4" colspan="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_PosY">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="1" column="7" colspan="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_PosZ">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="3" column="9">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="3" column="10">
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotZ">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="5" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_ScaleX">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="5" column="4" colspan="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_ScaleY">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="5" column="6">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="5" column="7" colspan="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_ScaleZ">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0" colspan="11">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Position</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="11">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Rotation</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="11">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="3" column="7" colspan="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotY">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>W</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotW">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="label_11">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="3" column="4" colspan="2">
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotX">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<widget class="QPushButton" name="pushButton_SavePowerUp">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Save Powerup</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_NewPowerUp">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>New Powerup</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Ignored</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_Generate">
<property name="text">
<string>Generate</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1330</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>