From 61fb15b7d5ab2795e7e92b8b96ee143e2ef11919 Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Tue, 20 Aug 2024 16:24:37 -0300 Subject: [PATCH] separate files The code has been separated into separate files as suggested by georgemoralis. Added the Patch tab, which has not been implemented yet. Added the 'applyCheat' area to apply the modification, not implemented yet... And added LOG_INFO. --- CMakeLists.txt | 2 + src/qt_gui/cheats_patches.cpp | 237 +++++++++++++++++++++++++++++ src/qt_gui/cheats_patches.h | 56 +++++++ src/qt_gui/gui_context_menus.h | 268 ++------------------------------- 4 files changed, 306 insertions(+), 257 deletions(-) create mode 100644 src/qt_gui/cheats_patches.cpp create mode 100644 src/qt_gui/cheats_patches.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f4146bb..b2b2ceaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -552,6 +552,8 @@ qt_add_resources(RESOURCE_FILES src/shadps4.qrc) set(QT_GUI src/qt_gui/about_dialog.cpp src/qt_gui/about_dialog.h src/qt_gui/about_dialog.ui + src/qt_gui/cheats_patches.cpp + src/qt_gui/cheats_patches.h src/qt_gui/main_window_ui.h src/qt_gui/main_window.cpp src/qt_gui/main_window.h diff --git a/src/qt_gui/cheats_patches.cpp b/src/qt_gui/cheats_patches.cpp new file mode 100644 index 00000000..5677570c --- /dev/null +++ b/src/qt_gui/cheats_patches.cpp @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cheats_patches.h" +#include "common/path_util.h" + +CheatsPatches::CheatsPatches(const QString& gameName, const QString& gameSerial, + const QString& gameVersion, const QString& gameSize, + const QPixmap& gameImage, QWidget* parent) + : QWidget(parent), m_gameName(gameName), m_gameSerial(gameSerial), m_gameVersion(gameVersion), + m_gameSize(gameSize), m_gameImage(gameImage) { + setupUI(); + resize(800, 400); +} + +CheatsPatches::~CheatsPatches() {} + +void CheatsPatches::setupUI() { + const auto& CHEATS_DIR = Common::FS::GetUserPath(Common::FS::PathType::CheatsDir); + QString CHEATS_DIR_QString = QString::fromStdString(CHEATS_DIR.string()); + QString NameCheatJson = m_gameSerial + "_" + m_gameVersion + ".json"; + m_cheatFilePath = CHEATS_DIR_QString + "/" + NameCheatJson; + + QHBoxLayout* mainLayout = new QHBoxLayout(this); + + // Create the game info group box + QGroupBox* gameInfoGroupBox = new QGroupBox("Game Information"); + QVBoxLayout* gameInfoLayout = new QVBoxLayout(gameInfoGroupBox); + gameInfoLayout->setAlignment(Qt::AlignTop); + + QLabel* gameImageLabel = new QLabel(); + if (!m_gameImage.isNull()) { + gameImageLabel->setPixmap(m_gameImage.scaled(250, 250, Qt::KeepAspectRatio)); + } else { + gameImageLabel->setText("No Image Available"); + } + gameImageLabel->setAlignment(Qt::AlignCenter); + gameInfoLayout->addWidget(gameImageLabel, 0, Qt::AlignCenter); + + QLabel* gameNameLabel = new QLabel(m_gameName); + gameNameLabel->setAlignment(Qt::AlignLeft); + gameNameLabel->setWordWrap(true); + gameInfoLayout->addWidget(gameNameLabel); + + QLabel* gameSerialLabel = new QLabel("Serial: " + m_gameSerial); + gameSerialLabel->setAlignment(Qt::AlignLeft); + gameInfoLayout->addWidget(gameSerialLabel); + + QLabel* gameVersionLabel = new QLabel("Version: " + m_gameVersion); + gameVersionLabel->setAlignment(Qt::AlignLeft); + gameInfoLayout->addWidget(gameVersionLabel); + + QLabel* gameSizeLabel = new QLabel("Size: " + m_gameSize); + gameSizeLabel->setAlignment(Qt::AlignLeft); + gameInfoLayout->addWidget(gameSizeLabel); + + // Create the tab widget + QTabWidget* tabWidget = new QTabWidget(); + QWidget* cheatsTab = new QWidget(); + QWidget* patchesTab = new QWidget(); + + // Layouts for the tabs + QVBoxLayout* cheatsLayout = new QVBoxLayout(); + QVBoxLayout* patchesLayout = new QVBoxLayout(); + + // Setup the cheats tab + QGroupBox* cheatsGroupBox = new QGroupBox("Cheats"); + rightLayout = new QVBoxLayout(cheatsGroupBox); + checkBoxStyle = "QCheckBox { font-size: 19px; }"; + buttonStyle = "QPushButton { font-size: 19px; }"; + rightLayout->setAlignment(Qt::AlignTop); + + loadCheats(m_cheatFilePath); + cheatsGroupBox->setLayout(rightLayout); + QScrollArea* scrollArea = new QScrollArea(); + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(cheatsGroupBox); + cheatsLayout->addWidget(scrollArea); + + // Add a check for updates button + QHBoxLayout* buttonLayout = new QHBoxLayout(); + QPushButton* checkUpdateButton = new QPushButton("Download Cheats"); + connect(checkUpdateButton, &QPushButton::clicked, [=]() { + if (QFile::exists(m_cheatFilePath)) { + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "File Exists", + "File already exists. Do you want to replace it?", + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::No) { + return; + } + } + + const QString url = + "https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/main/json/" + + m_gameSerial + "_" + m_gameVersion + ".json"; + + QNetworkAccessManager* manager = new QNetworkAccessManager(this); + QNetworkRequest request(url); + QNetworkReply* reply = manager->get(request); + + connect(reply, &QNetworkReply::finished, [=]() { + if (reply->error() == QNetworkReply::NoError) { + QByteArray jsonData = reply->readAll(); + QFile cheatFile(m_cheatFilePath); + if (cheatFile.open(QIODevice::WriteOnly)) { + cheatFile.write(jsonData); + cheatFile.close(); + loadCheats(m_cheatFilePath); + } + } else { + QMessageBox::warning(this, "Cheats/Patches not found", + "No Cheats/Patches found for this game in this version."); + } + reply->deleteLater(); + }); + }); + buttonLayout->addWidget(checkUpdateButton); + cheatsLayout->addLayout(buttonLayout); + cheatsTab->setLayout(cheatsLayout); + patchesTab->setLayout(patchesLayout); + tabWidget->addTab(cheatsTab, "Cheats"); + tabWidget->addTab(patchesTab, "Patches"); + mainLayout->addWidget(gameInfoGroupBox, 1); + mainLayout->addWidget(tabWidget, 3); + setLayout(mainLayout); +} + +void CheatsPatches::loadCheats(const QString& filePath) { + QFile file(filePath); + if (file.open(QIODevice::ReadOnly)) { + QByteArray jsonData = file.readAll(); + QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); + QJsonObject jsonObject = jsonDoc.object(); + QJsonArray modsArray = jsonObject["mods"].toArray(); + addMods(modsArray); + } +} + +void CheatsPatches::addMods(const QJsonArray& modsArray) { + QLayoutItem* item; + while ((item = rightLayout->takeAt(0)) != nullptr) { + delete item->widget(); + delete item; + } + m_cheats.clear(); + + for (const QJsonValue& modValue : modsArray) { + QJsonObject modObject = modValue.toObject(); + QString modName = modObject["name"].toString(); + QString modType = modObject["type"].toString(); + + Cheat cheat; + cheat.name = modName; + cheat.type = modType; + + QJsonArray memoryArray = modObject["memory"].toArray(); + for (const QJsonValue& memoryValue : memoryArray) { + QJsonObject memoryObject = memoryValue.toObject(); + MemoryMod memoryMod; + memoryMod.offset = memoryObject["offset"].toString(); + memoryMod.on = memoryObject["on"].toString(); + memoryMod.off = memoryObject["off"].toString(); + cheat.memoryMods.append(memoryMod); + } + + m_cheats[modName] = cheat; + + if (modType == "checkbox") { + QCheckBox* cheatCheckBox = new QCheckBox(modName); + cheatCheckBox->setStyleSheet(checkBoxStyle); + rightLayout->addWidget(cheatCheckBox); + connect(cheatCheckBox, &QCheckBox::toggled, + [=](bool checked) { applyCheat(modName, checked); }); + } else if (modType == "button") { + QPushButton* cheatButton = new QPushButton(modName); + cheatButton->setStyleSheet(buttonStyle); + rightLayout->addWidget(cheatButton); + connect(cheatButton, &QPushButton::clicked, [=]() { applyCheat(modName, true); }); + } + } + + QLabel* creditsLabel = new QLabel(); + QString creditsText = "Author: "; + + QFile file(m_cheatFilePath); + if (file.open(QIODevice::ReadOnly)) { + QByteArray jsonData = file.readAll(); + QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); + QJsonObject jsonObject = jsonDoc.object(); + QJsonArray creditsArray = jsonObject["credits"].toArray(); + for (const QJsonValue& creditValue : creditsArray) { + creditsText += creditValue.toString() + ", "; + } + if (creditsText.endsWith(", ")) { + creditsText.chop(2); + } + } + creditsLabel->setText(creditsText); + creditsLabel->setAlignment(Qt::AlignLeft); + rightLayout->addWidget(creditsLabel); +} + +void CheatsPatches::applyCheat(const QString& modName, bool enabled) { + if (!m_cheats.contains(modName)) + return; + + Cheat cheat = m_cheats[modName]; + + for (const MemoryMod& memoryMod : cheat.memoryMods) { + QString value = enabled ? memoryMod.on : memoryMod.off; + + std::string modNameStr = modName.toStdString(); + std::string offsetStr = memoryMod.offset.toStdString(); + std::string valueStr = value.toStdString(); + + LOG_INFO(Loader, "Cheat applied:{}, Offset:{}, Value:{}", modNameStr, offsetStr, valueStr); + + // Implement + // Send a request to modify the process memory. + } +} diff --git a/src/qt_gui/cheats_patches.h b/src/qt_gui/cheats_patches.h new file mode 100644 index 00000000..329b9aec --- /dev/null +++ b/src/qt_gui/cheats_patches.h @@ -0,0 +1,56 @@ +#ifndef CHEATS_PATCHES_H +#define CHEATS_PATCHES_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class CheatsPatches : public QWidget { + Q_OBJECT + +public: + CheatsPatches(const QString& gameName, const QString& gameSerial, const QString& gameVersion, + const QString& gameSize, const QPixmap& gameImage, QWidget* parent = nullptr); + ~CheatsPatches(); + +private: + void setupUI(); + void loadCheats(const QString& filePath); + void addMods(const QJsonArray& modsArray); + void applyCheat(const QString& modName, bool enabled); + + struct MemoryMod { + QString offset; + QString on; + QString off; + }; + + struct Cheat { + QString name; + QString type; + QVector memoryMods; + }; + + QString m_gameName; + QString m_gameSerial; + QString m_gameVersion; + QString m_gameSize; + QPixmap m_gameImage; + QString m_cheatFilePath; + + QVBoxLayout* rightLayout; + QString checkBoxStyle; + QString buttonStyle; + + QMap m_cheats; +}; + +#endif // CHEATS_PATCHES_H diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index 35acb1d3..f217b1c7 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -3,27 +3,22 @@ #pragma once -#include #include #include #include #include -#include #include #include #include #include #include -#include -#include #include #include #include #include #include -#include -#include +#include "cheats_patches.h" #include "game_info.h" #include "trophy_viewer.h" @@ -139,257 +134,16 @@ public: } if (selected == &openCheats) { - const auto& CHEATS_DIR = Common::FS::GetUserPath(Common::FS::PathType::CheatsDir); - QString CHEATS_DIR_QString = QString::fromStdString(CHEATS_DIR.string()); - const QString NameCheatJson = QString::fromStdString(m_games[itemID].serial) + "_" + - QString::fromStdString(m_games[itemID].version) + ".json"; - const QString cheatFilePath = CHEATS_DIR_QString + "/" + NameCheatJson; - - QWidget* cheatWidget = new QWidget(); - cheatWidget->setAttribute(Qt::WA_DeleteOnClose); - cheatWidget->setWindowTitle("Cheats/Patches"); - cheatWidget->resize(700, 300); - - QVBoxLayout* mainLayout = new QVBoxLayout(cheatWidget); - QHBoxLayout* horizontalLayout = new QHBoxLayout(); - - // GroupBox for game information (Left side) - QGroupBox* gameInfoGroupBox = new QGroupBox(); - QVBoxLayout* leftLayout = new QVBoxLayout(gameInfoGroupBox); - leftLayout->setAlignment(Qt::AlignTop); - - // Game image - QLabel* gameImage = new QLabel(); - QPixmap pixmap(QString::fromStdString(m_games[itemID].icon_path)); - gameImage->setPixmap(pixmap.scaled(250, 250, Qt::KeepAspectRatio)); - gameImage->setAlignment(Qt::AlignCenter); - leftLayout->addWidget(gameImage, 0, Qt::AlignCenter); - - // Game name - QLabel* gameName = new QLabel(QString::fromStdString(m_games[itemID].name)); - gameName->setAlignment(Qt::AlignLeft); - gameName->setWordWrap(true); - leftLayout->addWidget(gameName); - - // Game serial - QLabel* gameSerial = - new QLabel("Serial: " + QString::fromStdString(m_games[itemID].serial)); - gameSerial->setAlignment(Qt::AlignLeft); - leftLayout->addWidget(gameSerial); - - // Game version - QLabel* gameVersion = - new QLabel("Version: " + QString::fromStdString(m_games[itemID].version)); - gameVersion->setAlignment(Qt::AlignLeft); - leftLayout->addWidget(gameVersion); - - // Game size - QLabel* gameSize = new QLabel("Size: " + QString::fromStdString(m_games[itemID].size)); - gameSize->setAlignment(Qt::AlignLeft); - leftLayout->addWidget(gameSize); - - // Check for credits and add QLabel if exists - QFile file(cheatFilePath); - if (file.open(QIODevice::ReadOnly)) { - QByteArray jsonData = file.readAll(); - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); - QJsonObject jsonObject = jsonDoc.object(); - - if (jsonObject.contains("credits")) { - QJsonArray creditsArray = jsonObject["credits"].toArray(); - if (!creditsArray.isEmpty()) { - QStringList creditsList; - for (const QJsonValue& value : creditsArray) { - creditsList.append(value.toString()); - } - QString credits = creditsList.join(", "); - QLabel* creditsLabel = new QLabel("Author: " + credits); - creditsLabel->setAlignment(Qt::AlignLeft); - leftLayout->addWidget(creditsLabel); - } - } - } - - gameInfoGroupBox->setLayout(leftLayout); - horizontalLayout->addWidget(gameInfoGroupBox); - QScrollArea* scrollArea = new QScrollArea(); - scrollArea->setWidgetResizable(true); - - // Right - QGroupBox* cheatsGroupBox = new QGroupBox(); - QVBoxLayout* rightLayout = new QVBoxLayout(cheatsGroupBox); - QString checkBoxStyle = "QCheckBox { font-size: 19px; }"; - QString buttonStyle = "QPushButton { font-size: 19px; }"; - rightLayout->setAlignment(Qt::AlignTop); - - // Function to add checkboxes and buttons to the layout - auto addMods = [=](const QJsonArray& modsArray) { - // Limpar widgets existentes - QLayoutItem* item; - while ((item = rightLayout->takeAt(0)) != nullptr) { - delete item->widget(); - delete item; - } - - for (const QJsonValue& modValue : modsArray) { - QJsonObject modObject = modValue.toObject(); - QString modName = modObject["name"].toString(); - QString modType = modObject["type"].toString(); - - if (modType == "checkbox") { - bool isEnabled = modObject.contains("is_enabled") - ? modObject["is_enabled"].toBool() - : false; - QCheckBox* cheatCheckBox = new QCheckBox(modName); - cheatCheckBox->setStyleSheet(checkBoxStyle); - cheatCheckBox->setChecked(isEnabled); - rightLayout->addWidget(cheatCheckBox); - - // Connect the toggled(bool) signal to handle state change - connect(cheatCheckBox, &QCheckBox::toggled, [=](bool checked) { - if (checked) { - // Implement action when checkbox is checked - } else { - // Implement action when checkbox is unchecked - } - }); - } else if (modType == "button") { - QPushButton* cheatButton = new QPushButton(modName); - cheatButton->setStyleSheet(buttonStyle); - connect(cheatButton, &QPushButton::clicked, [=]() { - // Implementar a ação do botão !!! - }); - rightLayout->addWidget(cheatButton); - } - } - }; - - QNetworkAccessManager* manager = new QNetworkAccessManager(cheatWidget); - - auto loadCheats = [=](const QString& filePath) { - QFile file(filePath); - if (file.open(QIODevice::ReadOnly)) { - QByteArray jsonData = file.readAll(); - QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); - QJsonObject jsonObject = jsonDoc.object(); - QJsonArray modsArray = jsonObject["mods"].toArray(); - addMods(modsArray); - } - }; - - loadCheats(cheatFilePath); - cheatsGroupBox->setLayout(rightLayout); - scrollArea->setWidget(cheatsGroupBox); - horizontalLayout->addWidget(scrollArea); - mainLayout->addLayout(horizontalLayout); - - QHBoxLayout* buttonLayout = new QHBoxLayout(); - QPushButton* checkUpdateButton = new QPushButton("Check Update"); - QPushButton* cancelButton = new QPushButton("Cancel"); - QPushButton* saveButton = new QPushButton("Save"); - - connect(checkUpdateButton, &QPushButton::clicked, [=]() { - if (QFile::exists(cheatFilePath)) { - QMessageBox::StandardButton reply; - reply = QMessageBox::question(cheatWidget, "File Exists", - "File already exists. Do you want to replace it?", - QMessageBox::Yes | QMessageBox::No); - if (reply == QMessageBox::No) { - return; - } - } - - // Cheats repository URL, replace with a synced fork of the repository - const QString url = "https://raw.githubusercontent.com/GoldHEN/" - "GoldHEN_Cheat_Repository/main/json/" + - NameCheatJson; - - QNetworkRequest request(url); - QNetworkReply* reply = manager->get(request); - - connect(reply, &QNetworkReply::finished, [=]() { - if (reply->error() == QNetworkReply::NoError) { - QByteArray jsonData = reply->readAll(); - - // Save the JSON file in the cheats folder - QFile cheatFile(cheatFilePath); - if (cheatFile.open(QIODevice::WriteOnly)) { - cheatFile.write(jsonData); - cheatFile.close(); - } - - // Reload and add new widgets - loadCheats(cheatFilePath); - } else { - QMessageBox::warning( - cheatWidget, "Cheats/Patches not found", - "No Cheats/Patches found for this game in this version."); - } - - reply->deleteLater(); - }); - }); - - connect(cancelButton, &QPushButton::clicked, [=]() { cheatWidget->close(); }); - - connect(saveButton, &QPushButton::clicked, [=]() { - QJsonDocument jsonDoc; - QFile file(cheatFilePath); - if (file.open(QIODevice::ReadOnly)) { - jsonDoc = QJsonDocument::fromJson(file.readAll()); - file.close(); - } - - QJsonObject json = jsonDoc.object(); - QJsonArray modsArray = json["mods"].toArray(); - - QMap modMap; - for (int i = 0; i < rightLayout->count(); ++i) { - QWidget* widget = rightLayout->itemAt(i)->widget(); - if (QCheckBox* checkBox = qobject_cast(widget)) { - modMap[checkBox->text()] = checkBox->isChecked(); - } - // Buttons don't need state saving, so we ignore them. - } - - for (auto it = modMap.begin(); it != modMap.end(); ++it) { - bool found = false; - for (int i = 0; i < modsArray.size(); ++i) { - QJsonObject mod = modsArray[i].toObject(); - if (mod["name"].toString() == it.key()) { - mod["is_enabled"] = it.value(); - modsArray[i] = mod; - found = true; - break; - } - } - if (!found) { - QJsonObject newMod; - newMod["name"] = it.key(); - newMod["is_enabled"] = it.value(); - modsArray.append(newMod); - } - } - - json["mods"] = modsArray; - jsonDoc.setObject(json); - - if (file.open(QIODevice::WriteOnly)) { - file.write(jsonDoc.toJson()); - file.close(); - QMessageBox::information(cheatWidget, "Save", "Settings saved."); - cheatWidget->close(); - } else { - QMessageBox::warning(cheatWidget, "Error", "Could not open file for writing."); - } - }); - - buttonLayout->addWidget(checkUpdateButton); - buttonLayout->addWidget(cancelButton); - buttonLayout->addWidget(saveButton); - mainLayout->addLayout(buttonLayout); - cheatWidget->setLayout(mainLayout); - cheatWidget->show(); + QString gameName = QString::fromStdString(m_games[itemID].name); + QString gameSerial = QString::fromStdString(m_games[itemID].serial); + QString gameVersion = QString::fromStdString(m_games[itemID].version); + QString gameSize = QString::fromStdString(m_games[itemID].size); + QPixmap gameImage(QString::fromStdString(m_games[itemID].icon_path)); + CheatsPatches* cheatsPatches = + new CheatsPatches(gameName, gameSerial, gameVersion, gameSize, gameImage); + cheatsPatches->show(); + connect(widget->parent(), &QWidget::destroyed, cheatsPatches, + [widget, cheatsPatches]() { cheatsPatches->deleteLater(); }); } if (selected == &openTrophyViewer) {