Management |save checkbox | shadps4 repository

MENU - Cheats/Patches Management (implementing Patches)
save patches checkbox
add shadps4 repository
This commit is contained in:
DanielSvoboda 2024-08-26 12:00:15 -03:00
parent 9107c6e8c0
commit 3ac48b2d61
9 changed files with 697 additions and 184 deletions

View File

@ -548,6 +548,8 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/about_dialog.ui src/qt_gui/about_dialog.ui
src/qt_gui/cheats_patches.cpp src/qt_gui/cheats_patches.cpp
src/qt_gui/cheats_patches.h src/qt_gui/cheats_patches.h
src/qt_gui/cheats_patches_management.cpp
src/qt_gui/cheats_patches_management.h
src/qt_gui/main_window_ui.h src/qt_gui/main_window_ui.h
src/qt_gui/main_window.cpp src/qt_gui/main_window.cpp
src/qt_gui/main_window.h src/qt_gui/main_window.h

View File

@ -40,18 +40,18 @@ CheatsPatches::CheatsPatches(const QString& gameName, const QString& gameSerial,
: QWidget(parent), m_gameName(gameName), m_gameSerial(gameSerial), m_gameVersion(gameVersion), : QWidget(parent), m_gameName(gameName), m_gameSerial(gameSerial), m_gameVersion(gameVersion),
m_gameSize(gameSize), m_gameImage(gameImage), manager(new QNetworkAccessManager(this)) { m_gameSize(gameSize), m_gameImage(gameImage), manager(new QNetworkAccessManager(this)) {
setupUI(); setupUI();
resize(700, 400); resize(700, 350);
setWindowTitle("Cheats / Patches"); setWindowTitle("Cheats / Patches");
} }
CheatsPatches::~CheatsPatches() {} CheatsPatches::~CheatsPatches() {}
QString defaultTextEdit = QString defaultTextEdit =
("Cheat/Patches are experimental. Use with caution.\n" ("Cheat/Patches are experimental. Use with caution.\n\n"
"Select the repository from which you want to download cheats for this game and version and " "Download the cheats individually by selecting the repository and clicking the download "
"click the button. Since we do not develop Cheat/Patches, if you encounter issues or want to " "button.\nIn the Patch tab you can download all Patches at once, choose which one you want "
"suggest new ones, please send your feedback to:\n" "to use and save the option.\n\n"
"link not available yet :D"); "As we do not develop the Cheat/Patches,\nplease report issues related to the cheat author.");
void CheatsPatches::setupUI() { void CheatsPatches::setupUI() {
QString CHEATS_DIR_QString = QString CHEATS_DIR_QString =
@ -68,7 +68,7 @@ void CheatsPatches::setupUI() {
QLabel* gameImageLabel = new QLabel(); QLabel* gameImageLabel = new QLabel();
if (!m_gameImage.isNull()) { if (!m_gameImage.isNull()) {
gameImageLabel->setPixmap(m_gameImage.scaled(300, 300, Qt::KeepAspectRatio)); gameImageLabel->setPixmap(m_gameImage.scaled(275, 275, Qt::KeepAspectRatio));
} else { } else {
gameImageLabel->setText("No Image Available"); gameImageLabel->setText("No Image Available");
} }
@ -96,7 +96,7 @@ void CheatsPatches::setupUI() {
instructionsTextEdit = new QTextEdit(); instructionsTextEdit = new QTextEdit();
instructionsTextEdit->setText(defaultTextEdit); instructionsTextEdit->setText(defaultTextEdit);
instructionsTextEdit->setReadOnly(true); instructionsTextEdit->setReadOnly(true);
instructionsTextEdit->setFixedHeight(130); instructionsTextEdit->setFixedHeight(170);
gameInfoLayout->addWidget(instructionsTextEdit); gameInfoLayout->addWidget(instructionsTextEdit);
// Create the tab widget // Create the tab widget
@ -145,25 +145,20 @@ void CheatsPatches::setupUI() {
controlLayout->setAlignment(Qt::AlignLeft); controlLayout->setAlignment(Qt::AlignLeft);
QComboBox* downloadComboBox = new QComboBox(); QComboBox* downloadComboBox = new QComboBox();
auto urlCheat_wolf2022 = "https://wolf2022.ir/trainer/" + NameCheatJson; downloadComboBox->addItem("wolf2022", "wolf2022");
downloadComboBox->addItem("wolf2022", urlCheat_wolf2022);
downloadComboBox->addItem("GoldHEN", "GoldHEN"); downloadComboBox->addItem("GoldHEN", "GoldHEN");
downloadComboBox->addItem("shadPS4", "shadPS4");
controlLayout->addWidget(downloadComboBox); controlLayout->addWidget(downloadComboBox);
QPushButton* downloadButton = new QPushButton("Download Cheats"); QPushButton* downloadButton = new QPushButton("Download Cheats");
connect(downloadButton, &QPushButton::clicked, [=]() { connect(downloadButton, &QPushButton::clicked, [=]() {
QString url = downloadComboBox->currentData().toString(); QString source = downloadComboBox->currentData().toString();
if (url == "GoldHEN") { downloadCheats(source, m_gameSerial, m_gameVersion, true);
downloadFilesGoldHEN();
} else {
downloadCheats(url);
}
}); });
QPushButton* removeCheatButton = new QPushButton("Delete File"); QPushButton* deleteCheatButton = new QPushButton("Delete File");
connect(removeCheatButton, &QPushButton::clicked, [=]() { connect(deleteCheatButton, &QPushButton::clicked, [=]() {
QStringListModel* model = qobject_cast<QStringListModel*>(listView_selectFile->model()); QStringListModel* model = qobject_cast<QStringListModel*>(listView_selectFile->model());
if (!model) { if (!model) {
return; return;
@ -196,7 +191,7 @@ void CheatsPatches::setupUI() {
}); });
controlLayout->addWidget(downloadButton); controlLayout->addWidget(downloadButton);
controlLayout->addWidget(removeCheatButton); controlLayout->addWidget(deleteCheatButton);
cheatsLayout->addLayout(controlLayout); cheatsLayout->addLayout(controlLayout);
cheatsTab->setLayout(cheatsLayout); cheatsTab->setLayout(cheatsLayout);
@ -205,6 +200,7 @@ void CheatsPatches::setupUI() {
QGroupBox* patchesGroupBox = new QGroupBox(); QGroupBox* patchesGroupBox = new QGroupBox();
patchesGroupBoxLayout = new QVBoxLayout(patchesGroupBox); patchesGroupBoxLayout = new QVBoxLayout(patchesGroupBox);
patchesGroupBoxLayout->setAlignment(Qt::AlignTop); patchesGroupBoxLayout->setAlignment(Qt::AlignTop);
patchesGroupBox->setLayout(patchesGroupBoxLayout);
QScrollArea* patchesScrollArea = new QScrollArea(); QScrollArea* patchesScrollArea = new QScrollArea();
patchesScrollArea->setWidgetResizable(true); patchesScrollArea->setWidgetResizable(true);
@ -216,8 +212,13 @@ void CheatsPatches::setupUI() {
QPushButton* patchesButton = new QPushButton("Download All Available Patches"); QPushButton* patchesButton = new QPushButton("Download All Available Patches");
connect(patchesButton, &QPushButton::clicked, [=]() { downloadPatches(); }); connect(patchesButton, &QPushButton::clicked, [=]() { downloadPatches(); });
patchesControlLayout->addWidget(patchesButton); patchesControlLayout->addWidget(patchesButton);
QPushButton* saveButton = new QPushButton("Save");
connect(saveButton, &QPushButton::clicked, this, &CheatsPatches::onSaveButtonClicked);
patchesControlLayout->addWidget(saveButton);
patchesLayout->addLayout(patchesControlLayout); patchesLayout->addLayout(patchesControlLayout);
patchesTab->setLayout(patchesLayout); patchesTab->setLayout(patchesLayout);
@ -235,9 +236,167 @@ void CheatsPatches::setupUI() {
setLayout(mainLayout); setLayout(mainLayout);
} }
void CheatsPatches::downloadFilesGoldHEN() { void CheatsPatches::onSaveButtonClicked() {
QString url = QString patchDir =
"https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/main/json.txt"; QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string());
QString filesJsonPath = patchDir + "/files.json";
QFile jsonFile(filesJsonPath);
if (!jsonFile.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this, "Error", "Unable to open files.json for reading.");
return;
}
QByteArray jsonData = jsonFile.readAll();
jsonFile.close();
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
QJsonObject jsonObject = jsonDoc.object();
QString selectedFileName;
QString serial = m_gameSerial;
for (auto it = jsonObject.constBegin(); it != jsonObject.constEnd(); ++it) {
QString filePath = it.key();
QJsonArray idsArray = it.value().toArray();
if (idsArray.contains(QJsonValue(serial))) {
selectedFileName = filePath;
break;
}
}
if (selectedFileName.isEmpty()) {
QMessageBox::critical(this, "Error", "No patch file found for the current serial.");
return;
}
QString filePath = patchDir + "/" + selectedFileName;
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox::critical(this, "Error", "Unable to open the file for reading.");
return;
}
QByteArray xmlData = file.readAll();
file.close();
QString newXmlData;
QXmlStreamWriter xmlWriter(&newXmlData);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
QXmlStreamReader xmlReader(xmlData);
bool insideMetadata = false;
while (!xmlReader.atEnd()) {
xmlReader.readNext();
if (xmlReader.isStartElement()) {
if (xmlReader.name() == QStringLiteral("Metadata")) {
insideMetadata = true;
xmlWriter.writeStartElement(xmlReader.name().toString());
QString name = xmlReader.attributes().value("Name").toString();
bool isEnabled = false;
bool hasIsEnabled = false;
// Check and update the isEnabled attribute
for (const QXmlStreamAttribute& attr : xmlReader.attributes()) {
if (attr.name() == QStringLiteral("isEnabled")) {
hasIsEnabled = true;
auto it = m_patchInfos.find(name);
if (it != m_patchInfos.end()) {
QCheckBox* checkBox = findCheckBoxByName(it->name);
if (checkBox) {
isEnabled = checkBox->isChecked();
xmlWriter.writeAttribute("isEnabled", isEnabled ? "true" : "false");
}
}
} else {
xmlWriter.writeAttribute(attr.name().toString(), attr.value().toString());
}
}
if (!hasIsEnabled) {
auto it = m_patchInfos.find(name);
if (it != m_patchInfos.end()) {
QCheckBox* checkBox = findCheckBoxByName(it->name);
if (checkBox) {
isEnabled = checkBox->isChecked();
}
}
xmlWriter.writeAttribute("isEnabled", isEnabled ? "true" : "false");
}
} else {
xmlWriter.writeStartElement(xmlReader.name().toString());
for (const QXmlStreamAttribute& attr : xmlReader.attributes()) {
xmlWriter.writeAttribute(attr.name().toString(), attr.value().toString());
}
}
} else if (xmlReader.isEndElement()) {
if (xmlReader.name() == QStringLiteral("Metadata")) {
insideMetadata = false;
}
xmlWriter.writeEndElement();
} else if (xmlReader.isCharacters() && !xmlReader.isWhitespace()) {
xmlWriter.writeCharacters(xmlReader.text().toString());
}
}
xmlWriter.writeEndDocument();
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(this, "Error", "Unable to open the file for writing.");
return;
}
QTextStream textStream(&file);
textStream << newXmlData;
file.close();
if (xmlReader.hasError()) {
QMessageBox::critical(this, "Error", "Failed to parse XML: " + xmlReader.errorString());
} else {
QMessageBox::information(this, "Success", "Options saved successfully.");
}
}
QCheckBox* CheatsPatches::findCheckBoxByName(const QString& name) {
for (int i = 0; i < patchesGroupBoxLayout->count(); ++i) {
QLayoutItem* item = patchesGroupBoxLayout->itemAt(i);
if (item) {
QWidget* widget = item->widget();
QCheckBox* checkBox = qobject_cast<QCheckBox*>(widget);
if (checkBox) {
if (checkBox->text() == name) {
return checkBox;
}
}
}
}
return nullptr;
}
void CheatsPatches::downloadCheats(const QString& source, const QString& m_gameSerial,
const QString& m_gameVersion, const bool showMessageBox) {
QDir dir(Common::FS::GetUserPath(Common::FS::PathType::CheatsDir));
if (!dir.exists()) {
dir.mkpath(".");
}
QString url;
if (source == "GoldHEN") {
url = "https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/main/json.txt";
} else if (source == "wolf2022") {
url = "https://wolf2022.ir/trainer/" + m_gameSerial + "_" + m_gameVersion + ".json";
} else if (source == "shadPS4") {
url = "https://raw.githubusercontent.com/shadps4-emu/ps4_cheats/main/"
"CHEATS_JSON.txt";
} else {
QMessageBox::warning(this, "Invalid Source", "The selected source is invalid.");
return;
}
QNetworkRequest request(url); QNetworkRequest request(url);
QNetworkReply* reply = manager->get(request); QNetworkReply* reply = manager->get(request);
@ -245,93 +404,146 @@ void CheatsPatches::downloadFilesGoldHEN() {
connect(reply, &QNetworkReply::finished, [=]() { connect(reply, &QNetworkReply::finished, [=]() {
if (reply->error() == QNetworkReply::NoError) { if (reply->error() == QNetworkReply::NoError) {
QByteArray jsonData = reply->readAll(); QByteArray jsonData = reply->readAll();
processJsonContent(jsonData); bool foundFiles = false;
} else {
QMessageBox::warning(
this, "Download Error",
QString("Unable to query the json.txt file from the GoldHEN repository.\nError: %1")
.arg(reply->errorString()));
}
reply->deleteLater();
});
connect(reply, &QNetworkReply::errorOccurred, [=](QNetworkReply::NetworkError code) { if (source == "GoldHEN" || source == "shadPS4") {
QMessageBox::warning(this, "Download Error", QString textContent(jsonData);
QString("Error in response: %1").arg(reply->errorString())); QRegularExpression regex(
}); QString("%1_%2[^=]*\.json").arg(m_gameSerial).arg(m_gameVersion));
} QRegularExpressionMatchIterator matches = regex.globalMatch(textContent);
QString baseUrl;
void CheatsPatches::processJsonContent(const QByteArray& jsonData) { if (source == "GoldHEN") {
bool foundFiles = false; baseUrl = "https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/"
QString textContent(jsonData); "main/json/";
QRegularExpression regex(QString("%1_%2[^=]*\.json").arg(m_gameSerial).arg(m_gameVersion)); } else {
QRegularExpressionMatchIterator matches = regex.globalMatch(textContent); baseUrl = "https://raw.githubusercontent.com/shadps4-emu/ps4_cheats/"
QString baseUrl = "main/CHEATS/";
"https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/main/json/"; }
QDir dir(Common::FS::GetUserPath(Common::FS::PathType::CheatsDir)); while (matches.hasNext()) {
if (!dir.exists()) { QRegularExpressionMatch match = matches.next();
dir.mkpath("."); QString fileName = match.captured(0);
}
while (matches.hasNext()) { if (!fileName.isEmpty()) {
QRegularExpressionMatch match = matches.next(); QString newFileName = fileName;
QString fileName = match.captured(0); int dotIndex = newFileName.lastIndexOf('.');
if (dotIndex != -1) {
if (!fileName.isEmpty()) { if (source == "GoldHEN") {
QString newFileName = fileName; newFileName.insert(dotIndex, "_GoldHEN");
int dotIndex = newFileName.lastIndexOf('.'); } else {
if (dotIndex != -1) { newFileName.insert(dotIndex, "_shadPS4");
newFileName.insert(dotIndex, "_GoldHEN"); }
}
QString fileUrl = baseUrl + fileName;
QString localFilePath = dir.filePath(newFileName);
if (QFile::exists(localFilePath) && showMessageBox) {
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) {
continue;
}
}
QNetworkRequest fileRequest(fileUrl);
QNetworkReply* fileReply = manager->get(fileRequest);
connect(fileReply, &QNetworkReply::finished, [=]() {
if (fileReply->error() == QNetworkReply::NoError) {
QByteArray fileData = fileReply->readAll();
QFile localFile(localFilePath);
if (localFile.open(QIODevice::WriteOnly)) {
localFile.write(fileData);
localFile.close();
} else {
QMessageBox::warning(
this, "Error Saving",
QString("Failed to save file: \n %1").arg(localFilePath));
}
} else {
QMessageBox::warning(
this, "Failed to Download",
QString("Failed to download file: %1\n\nError: %2")
.arg(fileUrl)
.arg(fileReply->errorString()));
}
fileReply->deleteLater();
});
foundFiles = true;
}
}
if (!foundFiles && showMessageBox) {
QMessageBox::warning(
this, "Cheats Not Found1",
"No Cheats found for this game in this version of the selected "
"repository,\n"
"try another repository or a different version of the game.");
}
} else if (source == "wolf2022") {
QString fileName = QFileInfo(QUrl(url).path()).fileName();
QString baseFileName = fileName;
int dotIndex = baseFileName.lastIndexOf('.');
if (dotIndex != -1) {
baseFileName.insert(dotIndex, "_wolf2022");
}
QString filePath =
QString::fromStdString(
Common::FS::GetUserPath(Common::FS::PathType::CheatsDir).string()) +
"/" + baseFileName;
if (QFile::exists(filePath) && showMessageBox) {
QMessageBox::StandardButton reply2;
reply2 = QMessageBox::question(
this, "File Exists", "File already exists. Do you want to replace it?",
QMessageBox::Yes | QMessageBox::No);
if (reply2 == QMessageBox::No) {
reply->deleteLater();
return;
}
}
QFile cheatFile(filePath);
if (cheatFile.open(QIODevice::WriteOnly)) {
cheatFile.write(jsonData);
cheatFile.close();
foundFiles = true;
populateFileListCheats();
} else {
QMessageBox::warning(this, "Error Saving",
QString("Failed to save file:\n %1").arg(filePath));
}
}
if (foundFiles && showMessageBox) {
QMessageBox::information(
this, "Cheats Downloaded Successfully",
"You have successfully downloaded the cheats\n"
"for this version of the game from the selected repository.\n\n"
"You can try downloading from another repository, if it is available "
"it will also be possible to use it by selecting the file from the list.");
populateFileListCheats();
} }
QString fileUrl = baseUrl + fileName; } else {
QString localFilePath = dir.filePath(newFileName); if (showMessageBox) {
QNetworkRequest fileRequest(fileUrl); QMessageBox::warning(
QNetworkReply* fileReply = manager->get(fileRequest); this, "Cheats Not Found",
"No Cheats found for this game in this version of the selected "
connect(fileReply, &QNetworkReply::finished, [=]() { "repository,\n"
if (fileReply->error() == QNetworkReply::NoError) { "try another repository or a different version of the game.");
QByteArray fileData = fileReply->readAll(); }
QFile localFile(localFilePath);
if (localFile.open(QIODevice::WriteOnly)) {
localFile.write(fileData);
localFile.close();
} else {
QMessageBox::warning(
this, "Error Saving",
QString("Failed to save file:\n %1").arg(localFilePath));
}
} else {
QMessageBox::warning(this, "Failed to Download",
QString("Failed to download file: %1\n\nError: %2")
.arg(fileUrl)
.arg(fileReply->errorString()));
}
fileReply->deleteLater();
});
// Marks that at least one file was found
foundFiles = true;
} }
} reply->deleteLater();
emit downloadFinished();
});
if (!foundFiles) { // connect(reply, &QNetworkReply::errorOccurred, [=](QNetworkReply::NetworkError code) {
QMessageBox::warning( // if (showMessageBox)
this, "Cheats Not Found", // QMessageBox::warning(this, "Download Error",
"No Cheats found for this game in this version of the selected repository,\n" // QString("Error in response: %1").arg(reply->errorString()));
"try another repository or a different version of the game."); // });
} else {
QMessageBox::information(
this, "Cheats Downloaded Successfully",
"You have successfully downloaded the cheats\n"
"for this version of the game from the 'GoldHEN' repository.\n\n"
"You can try downloading from another repository, if it is available it will also "
"be possible to use it by selecting the file from the list.");
;
populateFileListCheats();
}
} }
void CheatsPatches::onTabChanged(int index) { void CheatsPatches::onTabChanged(int index) {
@ -340,61 +552,6 @@ void CheatsPatches::onTabChanged(int index) {
} }
} }
void CheatsPatches::downloadCheats(const QString& url) {
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();
QString fileName = QFileInfo(QUrl(url).path()).fileName();
QString baseFileName = fileName;
int dotIndex = baseFileName.lastIndexOf('.');
if (dotIndex != -1) {
baseFileName.insert(dotIndex, "_wolf2022");
}
QString filePath =
QString::fromStdString(
Common::FS::GetUserPath(Common::FS::PathType::CheatsDir).string()) +
"/" + baseFileName;
if (QFile::exists(filePath)) {
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;
}
}
QFile cheatFile(filePath);
if (cheatFile.open(QIODevice::WriteOnly)) {
cheatFile.write(jsonData);
cheatFile.close();
populateFileListCheats();
} else {
QMessageBox::warning(this, "Error saving",
QString("Failed to save file:\n %1").arg(filePath));
}
QMessageBox::information(
this, "Cheats Downloaded Successfully",
"You have successfully downloaded the cheats\n"
"for this version of the game from the 'wolf2022' repository.\n\n"
"You can try downloading from another repository, if it is available it will also "
"be possible to use it by selecting the file from the list.");
} else {
QMessageBox::warning(
this, "Cheats Not Found",
"No Cheats found for this game in this version of the selected repository,\n"
"try another repository or a different version of the game.");
}
reply->deleteLater();
});
}
void CheatsPatches::downloadPatches() { void CheatsPatches::downloadPatches() {
QString url = "https://github.com/GoldHEN/GoldHEN_Patch_Repository/tree/main/" QString url = "https://github.com/GoldHEN/GoldHEN_Patch_Repository/tree/main/"
"patches/xml"; "patches/xml";
@ -482,7 +639,6 @@ void CheatsPatches::downloadPatches() {
} }
void CheatsPatches::createFilesJson() { void CheatsPatches::createFilesJson() {
// Directory where XML files are located
QString patchesDir = QString patchesDir =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string()); QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string());
QDir dir(patchesDir); QDir dir(patchesDir);
@ -680,7 +836,6 @@ void CheatsPatches::onFileSelected(const QModelIndex& index) {
} }
void CheatsPatches::loadCheats(const QString& filePath) { void CheatsPatches::loadCheats(const QString& filePath) {
QFile file(filePath); QFile file(filePath);
if (file.open(QIODevice::ReadOnly)) { if (file.open(QIODevice::ReadOnly)) {
QByteArray jsonData = file.readAll(); QByteArray jsonData = file.readAll();
@ -691,8 +846,8 @@ void CheatsPatches::loadCheats(const QString& filePath) {
addCheatsToLayout(modsArray, creditsArray); addCheatsToLayout(modsArray, creditsArray);
} }
} }
void CheatsPatches::loadPatches(const QString& serial) {
void CheatsPatches::loadPatches(const QString& serial) {
QLayoutItem* item; QLayoutItem* item;
while ((item = patchesGroupBoxLayout->takeAt(0)) != nullptr) { while ((item = patchesGroupBoxLayout->takeAt(0)) != nullptr) {
delete item->widget(); delete item->widget();
@ -733,6 +888,7 @@ void CheatsPatches::loadPatches(const QString& serial) {
QString patchAuthor; QString patchAuthor;
QString patchNote; QString patchNote;
QJsonArray patchLines; QJsonArray patchLines;
bool isEnabled = false;
while (!xmlReader.atEnd() && !xmlReader.hasError()) { while (!xmlReader.atEnd() && !xmlReader.hasError()) {
xmlReader.readNext(); xmlReader.readNext();
@ -745,11 +901,15 @@ void CheatsPatches::loadPatches(const QString& serial) {
patchName = attributes.value("Name").toString(); patchName = attributes.value("Name").toString();
patchAuthor = attributes.value("Author").toString(); patchAuthor = attributes.value("Author").toString();
patchNote = attributes.value("Note").toString(); patchNote = attributes.value("Note").toString();
isEnabled = isEnabled =
attributes.value("isEnabled").toString() == QStringLiteral("true");
} }
if (appVer == "mask") { if (appVer == "mask") {
patchName = attributes.value("Name").toString(); patchName = attributes.value("Name").toString() + " (any version)";
patchAuthor = attributes.value("Author").toString(); patchAuthor = attributes.value("Author").toString();
patchNote = attributes.value("Note").toString(); patchNote = attributes.value("Note").toString();
isEnabled = isEnabled =
attributes.value("isEnabled").toString() == QStringLiteral("true");
} }
} else if (xmlReader.name() == QStringLiteral("PatchList")) { } else if (xmlReader.name() == QStringLiteral("PatchList")) {
QJsonArray linesArray; QJsonArray linesArray;
@ -772,7 +932,8 @@ void CheatsPatches::loadPatches(const QString& serial) {
} }
if (!patchName.isEmpty() && !patchLines.isEmpty()) { if (!patchName.isEmpty() && !patchLines.isEmpty()) {
addPatchToLayout(patchName, patchAuthor, patchNote, patchLines, serial); addPatchToLayout(patchName, patchAuthor, patchNote, patchLines, serial,
isEnabled);
patchName.clear(); patchName.clear();
patchAuthor.clear(); patchAuthor.clear();
patchNote.clear(); patchNote.clear();
@ -786,10 +947,12 @@ void CheatsPatches::loadPatches(const QString& serial) {
void CheatsPatches::addPatchToLayout(const QString& name, const QString& author, void CheatsPatches::addPatchToLayout(const QString& name, const QString& author,
const QString& note, const QJsonArray& linesArray, const QString& note, const QJsonArray& linesArray,
const QString& serial) { const QString& serial, bool isEnabled) {
QCheckBox* patchCheckBox = new QCheckBox(name); QCheckBox* patchCheckBox = new QCheckBox(name);
patchCheckBox->setChecked(
isEnabled); // Configura o estado do checkbox com base no valor isEnabled
patchesGroupBoxLayout->addWidget(patchCheckBox); patchesGroupBoxLayout->addWidget(patchCheckBox);
PatchInfo patchInfo; PatchInfo patchInfo;
patchInfo.name = name; patchInfo.name = name;
patchInfo.author = author; patchInfo.author = author;
@ -798,7 +961,6 @@ void CheatsPatches::addPatchToLayout(const QString& name, const QString& author,
patchInfo.serial = serial; patchInfo.serial = serial;
m_patchInfos[name] = patchInfo; m_patchInfos[name] = patchInfo;
// Hook checkbox hover events
patchCheckBox->installEventFilter(this); patchCheckBox->installEventFilter(this);
connect(patchCheckBox, &QCheckBox::toggled, [=](bool checked) { applyPatch(name, checked); }); connect(patchCheckBox, &QCheckBox::toggled, [=](bool checked) { applyPatch(name, checked); });
@ -850,9 +1012,6 @@ void CheatsPatches::applyCheat(const QString& modName, bool enabled) {
std::string offsetStr = memoryMod.offset.toStdString(); std::string offsetStr = memoryMod.offset.toStdString();
std::string valueStr = value.toStdString(); std::string valueStr = value.toStdString();
// Determine if the hint field is present
bool isHintPresent = m_cheats[modName].hasHint;
if (MemoryPatcher::g_eboot_address == 0) { if (MemoryPatcher::g_eboot_address == 0) {
MemoryPatcher::patchInfo addingPatch; MemoryPatcher::patchInfo addingPatch;
addingPatch.modNameStr = modNameStr; addingPatch.modNameStr = modNameStr;
@ -864,8 +1023,9 @@ void CheatsPatches::applyCheat(const QString& modName, bool enabled) {
continue; continue;
} }
bool isOffset = !isHintPresent; // Determine if the hint field is present
MemoryPatcher::PatchMemory(modNameStr, offsetStr, valueStr, isOffset, false); bool isHintPresent = m_cheats[modName].hasHint;
MemoryPatcher::PatchMemory(modNameStr, offsetStr, valueStr, !isHintPresent, false);
} }
} }
@ -1012,4 +1172,4 @@ void CheatsPatches::onPatchCheckBoxHovered(QCheckBox* checkBox, bool hovered) {
} else { } else {
instructionsTextEdit->setText(defaultTextEdit); instructionsTextEdit->setText(defaultTextEdit);
} }
} }

View File

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef CHEATS_PATCHES_H #ifndef CHEATS_PATCHES_H
#define CHEATS_PATCHES_H #define CHEATS_PATCHES_H
@ -31,31 +28,34 @@ public:
CheatsPatches(const QString& gameName, const QString& gameSerial, const QString& gameVersion, CheatsPatches(const QString& gameName, const QString& gameSerial, const QString& gameVersion,
const QString& gameSize, const QPixmap& gameImage, QWidget* parent = nullptr); const QString& gameSize, const QPixmap& gameImage, QWidget* parent = nullptr);
~CheatsPatches(); ~CheatsPatches();
void downloadCheats(const QString& source, const QString& m_gameSerial,
const QString& m_gameVersion, const bool showMessageBox);
void downloadPatches();
signals:
void downloadFinished();
private: private:
// UI Setup and Event Handlers // UI Setup and Event Handlers
void setupUI(); void setupUI();
void downloadFilesGoldHEN(); void onSaveButtonClicked();
void processJsonContent(const QByteArray& jsonData); QCheckBox* findCheckBoxByName(const QString& name);
void onTabChanged(int index); void onTabChanged(int index);
void updateNoteTextEdit(const QString& patchName); void updateNoteTextEdit(const QString& patchName);
// Cheat and Patch Management // Cheat and Patch Management
void populateFileListCheats(); void populateFileListCheats();
void onFileSelected(const QModelIndex& index); void onFileSelected(const QModelIndex& index);
void createFilesJson();
void uncheckAllCheatCheckBoxes();
void loadCheats(const QString& filePath); void loadCheats(const QString& filePath);
void loadPatches(const QString& serial); void loadPatches(const QString& serial);
void downloadCheats(const QString& url);
void downloadPatches();
void addCheatsToLayout(const QJsonArray& modsArray, const QJsonArray& creditsArray); void addCheatsToLayout(const QJsonArray& modsArray, const QJsonArray& creditsArray);
void addPatchToLayout(const QString& name, const QString& author, const QString& note, void addPatchToLayout(const QString& name, const QString& author, const QString& note,
const QJsonArray& linesArray, const QString& serial); const QJsonArray& linesArray, const QString& serial, bool isEnabled);
void createFilesJson();
void uncheckAllCheatCheckBoxes();
void applyCheat(const QString& modName, bool enabled); void applyCheat(const QString& modName, bool enabled);
void applyPatch(const QString& patchName, bool enabled); void applyPatch(const QString& patchName, bool enabled);
QString convertValueToHex(const QString& type, const QString& valueStr); QString convertValueToHex(const QString& type, const QString& valueStr);
@ -110,4 +110,4 @@ private:
QItemSelectionModel* selectionModel; QItemSelectionModel* selectionModel;
}; };
#endif // CHEATS_PATCHES_H #endif // CHEATS_PATCHES_H

View File

@ -0,0 +1,287 @@
#include <QApplication>
#include <QCheckBox>
#include <QDir>
#include <QFile>
#include <QFileInfoList>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QItemSelectionModel>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLabel>
#include <QListView>
#include <QMessageBox>
#include <QPushButton>
#include <QScrollArea>
#include <QStringListModel>
#include <QTabWidget>
#include <QTextEdit>
#include <QVBoxLayout>
#include "cheats_patches.h"
#include "cheats_patches_management.h"
#include "common/path_util.h"
using namespace Common::FS;
CheatsPatchesManagement::CheatsPatchesManagement(QObject* parent) : QObject(parent) {}
void CheatsPatchesManagement::setupCheatsManagementWidget(QWidget* parent) {
const auto& CHEATS_DIR = Common::FS::GetUserPath(Common::FS::PathType::CheatsDir);
QString CHEATS_DIR_QString = QString::fromStdString(CHEATS_DIR.string());
QWidget* cheatWidget = new QWidget(parent, Qt::Window);
cheatWidget->setAttribute(Qt::WA_DeleteOnClose);
cheatWidget->setWindowTitle("Cheats/Patches Management");
cheatWidget->resize(800, 800);
QVBoxLayout* mainLayout = new QVBoxLayout(cheatWidget);
QTabWidget* tabWidget = new QTabWidget();
QWidget* cheatsTab = new QWidget();
QVBoxLayout* cheatsLayout = new QVBoxLayout(cheatsTab);
listView_selectFile = new QListView();
listView_selectFile->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
listView_selectFile->setSelectionMode(QAbstractItemView::SingleSelection);
listView_selectFile->setEditTriggers(QAbstractItemView::NoEditTriggers);
QVBoxLayout* fileListLayout = new QVBoxLayout();
fileListLayout->addWidget(new QLabel("Select Cheat File:"));
fileListLayout->addWidget(listView_selectFile);
QPushButton* deleteCheatButton = new QPushButton("Delete File");
fileListLayout->addWidget(deleteCheatButton);
QString defaultTextEdit =
"With the button below 'Download' you can download Cheats for all games that are "
"installed on the emulator, they will be downloaded from all available repositories, "
"GoldHEN, wolf2022, shadPS4.\n"
"With the button 'Delete File' you can delete the chosen Cheat file from the list "
"above.\n\nIn the main menu, by right-clicking, you can open each game individually.";
QTextEdit* infoTextEdit = new QTextEdit();
infoTextEdit->setText(defaultTextEdit);
infoTextEdit->setReadOnly(true);
infoTextEdit->setFixedHeight(90);
fileListLayout->addWidget(infoTextEdit);
fileListLayout->setAlignment(Qt::AlignTop);
QWidget* leftWidget = new QWidget();
leftWidget->setLayout(fileListLayout);
leftWidget->setMinimumWidth(600);
QScrollArea* scrollArea = new QScrollArea();
scrollArea->setWidgetResizable(true);
QGroupBox* cheatsGroupBox = new QGroupBox();
rightLayout = new QVBoxLayout(cheatsGroupBox);
rightLayout->setAlignment(Qt::AlignTop);
cheatsGroupBox->setLayout(rightLayout);
scrollArea->setWidget(cheatsGroupBox);
QWidget* rightWidget = new QWidget();
QVBoxLayout* rightWidgetLayout = new QVBoxLayout(rightWidget);
rightWidgetLayout->addWidget(scrollArea);
rightWidget->setMinimumWidth(400);
QHBoxLayout* topLayout = new QHBoxLayout();
topLayout->addWidget(leftWidget);
topLayout->addWidget(rightWidget);
cheatsLayout->addLayout(topLayout);
QHBoxLayout* cheatsButtonLayout = new QHBoxLayout();
QPushButton* checkUpdateButton = new QPushButton("Download Cheats For All Installed Games");
connect(checkUpdateButton, &QPushButton::clicked, [this]() { onCheckUpdateButtonClicked(); });
connect(deleteCheatButton, &QPushButton::clicked, [=]() {
QStringListModel* model = qobject_cast<QStringListModel*>(listView_selectFile->model());
if (!model) {
return;
}
QItemSelectionModel* selectionModel = listView_selectFile->selectionModel();
QModelIndexList selectedIndexes = selectionModel->selectedIndexes();
if (!selectedIndexes.isEmpty()) {
int row = selectedIndexes.first().row();
QString selectedFileName = model->stringList().at(row);
QString filePath =
CHEATS_DIR_QString + "/" + selectedFileName.split("|").first().trimmed();
if (QFile::remove(filePath)) {
QMessageBox::information(cheatWidget, "File Deleted",
"File has been successfully deleted.");
populateFileListCheats();
} else {
QMessageBox::critical(cheatWidget, "File Deletion Failed",
"Failed to delete the selected file.");
}
}
});
cheatsButtonLayout->addWidget(checkUpdateButton);
cheatsButtonLayout->setAlignment(Qt::AlignBottom);
cheatsLayout->addLayout(cheatsButtonLayout);
tabWidget->addTab(cheatsTab, "CHEATS");
QWidget* patchesTab = new QWidget();
QVBoxLayout* patchesLayout = new QVBoxLayout(patchesTab);
QString default2TextEdit = "implementing :)";
QTextEdit* infoTextEdit2 = new QTextEdit();
infoTextEdit2->setText(default2TextEdit);
infoTextEdit2->setReadOnly(true);
infoTextEdit2->setFixedHeight(200);
patchesLayout->addWidget(infoTextEdit2);
tabWidget->addTab(patchesTab, "PATCHES");
mainLayout->addWidget(tabWidget);
cheatWidget->setLayout(mainLayout);
populateFileListCheats();
cheatWidget->show();
}
void CheatsPatchesManagement::setGameInfo(const QList<QPair<QString, QString>>& gameInfoPairs) {
m_gameInfoPairs = gameInfoPairs;
}
void CheatsPatchesManagement::onCheckUpdateButtonClicked() {
QEventLoop eventLoop;
int pendingDownloads = 0;
auto onDownloadFinished = [&]() {
if (--pendingDownloads <= 0) {
eventLoop.quit();
// Exit loop when all downloads are complete
}
};
for (const QPair<QString, QString>& gameInfo : m_gameInfoPairs) {
QString gameSerial = gameInfo.first;
QString gameVersion = gameInfo.second;
QString empty = "";
CheatsPatches* cheatsPatches =
new CheatsPatches(empty, empty, empty, empty, empty, nullptr);
connect(cheatsPatches, &CheatsPatches::downloadFinished, onDownloadFinished);
// Count how many downloads are in progress, 3 downloads for each game
pendingDownloads += 3;
cheatsPatches->downloadCheats("wolf2022", gameSerial, gameVersion, false);
cheatsPatches->downloadCheats("GoldHEN", gameSerial, gameVersion, false);
cheatsPatches->downloadCheats("shadPS4", gameSerial, gameVersion, false);
}
// Block until all downloads are complete
eventLoop.exec();
QMessageBox::information(nullptr, "Cheats Downloaded Successfully",
"You have downloaded cheats for all the games you have installed.\n\n"
"If you want, you can use the button to delete a file.");
populateFileListCheats();
}
void CheatsPatchesManagement::populateFileListCheats() {
const auto& CHEATS_DIR = Common::FS::GetUserPath(Common::FS::PathType::CheatsDir);
QString CHEATS_DIR_QString = QString::fromStdString(CHEATS_DIR.string());
QDir dir(CHEATS_DIR_QString);
QStringList filters;
filters << "*.json";
dir.setNameFilters(filters);
QFileInfoList fileList = dir.entryInfoList(QDir::Files);
QStringList fileNames;
QStringList filePaths;
for (const QFileInfo& fileInfo : fileList) {
fileNames << fileInfo.fileName();
filePaths << fileInfo.absoluteFilePath();
}
QStringList formattedFileNames;
for (int i = 0; i < fileNames.size(); ++i) {
QFile file(filePaths[i]);
if (file.open(QIODevice::ReadOnly)) {
QByteArray jsonData = file.readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
QJsonObject jsonObject = jsonDoc.object();
QString gameName = jsonObject["name"].toString();
formattedFileNames << QString("%1 | %2").arg(fileNames[i]).arg(gameName);
file.close();
}
}
QStringListModel* newModel = new QStringListModel(formattedFileNames, nullptr);
listView_selectFile->setModel(newModel);
connect(listView_selectFile->selectionModel(), &QItemSelectionModel::selectionChanged,
[this, filePaths, newModel]() {
QModelIndexList selectedIndexes =
listView_selectFile->selectionModel()->selectedIndexes();
if (!selectedIndexes.isEmpty()) {
QString selectedFilePath = filePaths[selectedIndexes.first().row()];
loadCheats(selectedFilePath);
} else {
addMods(QJsonArray());
}
});
if (!formattedFileNames.isEmpty()) {
QModelIndex firstIndex = newModel->index(0, 0);
listView_selectFile->selectionModel()->select(firstIndex, QItemSelectionModel::Select |
QItemSelectionModel::Rows);
listView_selectFile->setCurrentIndex(firstIndex);
QString selectedFilePath = filePaths.first();
loadCheats(selectedFilePath);
} else {
listView_selectFile->selectionModel()->clearSelection();
addMods(QJsonArray());
}
}
void CheatsPatchesManagement::addMods(const QJsonArray& modsArray) {
if (!rightLayout)
return;
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") {
QCheckBox* cheatCheckBox = new QCheckBox(modName);
cheatCheckBox->setChecked(false);
cheatCheckBox->setEnabled(false);
rightLayout->addWidget(cheatCheckBox);
} else if (modType == "button") {
QPushButton* cheatButton = new QPushButton(modName);
cheatButton->setEnabled(false);
rightLayout->addWidget(cheatButton);
}
}
}
void CheatsPatchesManagement::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);
}
}

View File

@ -0,0 +1,35 @@
#ifndef CHEATS_PATCHES_MANAGEMENT_H
#define CHEATS_PATCHES_MANAGEMENT_H
#include <QList>
#include <QListView>
#include <QString>
#include <QVBoxLayout>
#include <QWidget>
class CheatsPatchesManagement : public QObject {
Q_OBJECT
public:
explicit CheatsPatchesManagement(QObject* parent = nullptr);
void setupCheatsManagementWidget(QWidget* parent);
void setGameInfo(const QList<QPair<QString, QString>>& gameInfoPairs);
private:
void populateFileListCheats();
void populateFileListPatches();
void loadCheats(const QString& filePath);
void addMods(const QJsonArray& modsArray);
void onCheckUpdateButtonClicked();
void onCheckPatchesUpdateButtonClicked();
QList<QPair<QString, QString>> m_gameInfoPairs;
QListView* listView_selectFile;
QVBoxLayout* rightLayout;
QListView* patchesListView;
signals:
void downloadFinished();
};
#endif // CHEATS_PATCHES_MANAGEMENT_H

View File

@ -44,6 +44,11 @@ public:
itemID = widget->currentRow() * widget->columnCount() + widget->currentColumn(); itemID = widget->currentRow() * widget->columnCount() + widget->currentColumn();
} }
// Do not show the menu if an item is selected
if (itemID == -1) {
return;
}
// Setup menu. // Setup menu.
QMenu menu(widget); QMenu menu(widget);
QAction createShortcut("Create Shortcut", widget); QAction createShortcut("Create Shortcut", widget);

View File

@ -10,6 +10,7 @@
#include <QtConcurrent> #include <QtConcurrent>
#include "about_dialog.h" #include "about_dialog.h"
#include "cheats_patches.h"
#include "common/io_file.h" #include "common/io_file.h"
#include "common/version.h" #include "common/version.h"
#include "core/file_format/pkg.h" #include "core/file_format/pkg.h"
@ -313,6 +314,21 @@ void MainWindow::CreateConnects() {
Config::setTableMode(2); Config::setTableMode(2);
}); });
// Cheats Management.
connect(ui->cheatsManagementAct, &QAction::triggered, this, [this]() {
QList<QPair<QString, QString>> gameInfoPairs;
for (const GameInfo& game : m_game_info->m_games) {
QString gameSerial = QString::fromStdString(game.serial);
QString gameVersion = QString::fromStdString(game.version);
gameInfoPairs.append(qMakePair(gameSerial, gameVersion));
}
CheatsPatchesManagement* manager = new CheatsPatchesManagement(this);
manager->setGameInfo(gameInfoPairs);
manager->setupCheatsManagementWidget(this);
});
// Dump game list. // Dump game list.
connect(ui->dumpGameListAct, &QAction::triggered, this, [&] { connect(ui->dumpGameListAct, &QAction::triggered, this, [&] {
QString filePath = qApp->applicationDirPath().append("/GameList.txt"); QString filePath = qApp->applicationDirPath().append("/GameList.txt");

View File

@ -11,6 +11,7 @@
#include <QScopedPointer> #include <QScopedPointer>
#include <fmt/core.h> #include <fmt/core.h>
#include "cheats_patches_management.h"
#include "common/config.h" #include "common/config.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "core/file_format/psf.h" #include "core/file_format/psf.h"
@ -88,6 +89,8 @@ private:
PSF psf; PSF psf;
std::shared_ptr<GameInfoClass> m_game_info = std::make_shared<GameInfoClass>(); std::shared_ptr<GameInfoClass> m_game_info = std::make_shared<GameInfoClass>();
// Cheats/Patches Management.
QVBoxLayout* patchesRightLayout;
protected: protected:
void dragEnterEvent(QDragEnterEvent* event1) override { void dragEnterEvent(QDragEnterEvent* event1) override {

View File

@ -43,6 +43,7 @@ public:
QAction* setlistModeGridAct; QAction* setlistModeGridAct;
QAction* setlistElfAct; QAction* setlistElfAct;
QAction* gameInstallPathAct; QAction* gameInstallPathAct;
QAction* cheatsManagementAct;
QAction* dumpGameListAct; QAction* dumpGameListAct;
QAction* pkgViewerAct; QAction* pkgViewerAct;
QAction* aboutAct; QAction* aboutAct;
@ -138,11 +139,12 @@ public:
gameInstallPathAct = new QAction(MainWindow); gameInstallPathAct = new QAction(MainWindow);
gameInstallPathAct->setObjectName("gameInstallPathAct"); gameInstallPathAct->setObjectName("gameInstallPathAct");
gameInstallPathAct->setIcon(QIcon(":images/folder_icon.png")); gameInstallPathAct->setIcon(QIcon(":images/folder_icon.png"));
cheatsManagementAct = new QAction(MainWindow);
cheatsManagementAct->setObjectName("cheatsManagementAct");
dumpGameListAct = new QAction(MainWindow); dumpGameListAct = new QAction(MainWindow);
dumpGameListAct->setObjectName("dumpGameList"); dumpGameListAct->setObjectName("dumpGameList");
pkgViewerAct = new QAction(MainWindow); pkgViewerAct = new QAction(MainWindow);
pkgViewerAct->setObjectName("pkgViewer"); pkgViewerAct->setObjectName("pkgViewer");
pkgViewerAct->setObjectName("pkgViewer");
pkgViewerAct->setIcon(QIcon(":images/file_icon.png")); pkgViewerAct->setIcon(QIcon(":images/file_icon.png"));
aboutAct = new QAction(MainWindow); aboutAct = new QAction(MainWindow);
aboutAct->setObjectName("aboutAct"); aboutAct->setObjectName("aboutAct");
@ -295,6 +297,7 @@ public:
menuSettings->addAction(configureAct); menuSettings->addAction(configureAct);
menuSettings->addAction(gameInstallPathAct); menuSettings->addAction(gameInstallPathAct);
menuSettings->addAction(menuUtils->menuAction()); menuSettings->addAction(menuUtils->menuAction());
menuUtils->addAction(cheatsManagementAct);
menuUtils->addAction(dumpGameListAct); menuUtils->addAction(dumpGameListAct);
menuUtils->addAction(pkgViewerAct); menuUtils->addAction(pkgViewerAct);
menuAbout->addAction(aboutAct); menuAbout->addAction(aboutAct);
@ -341,6 +344,8 @@ public:
setlistElfAct->setText(QCoreApplication::translate("MainWindow", "Elf Viewer", nullptr)); setlistElfAct->setText(QCoreApplication::translate("MainWindow", "Elf Viewer", nullptr));
gameInstallPathAct->setText( gameInstallPathAct->setText(
QCoreApplication::translate("MainWindow", "Game Install Directory", nullptr)); QCoreApplication::translate("MainWindow", "Game Install Directory", nullptr));
cheatsManagementAct->setText(
QCoreApplication::translate("MainWindow", "Cheats Management", nullptr));
dumpGameListAct->setText( dumpGameListAct->setText(
QCoreApplication::translate("MainWindow", "Dump Game List", nullptr)); QCoreApplication::translate("MainWindow", "Dump Game List", nullptr));
pkgViewerAct->setText(QCoreApplication::translate("MainWindow", "PKG Viewer", nullptr)); pkgViewerAct->setText(QCoreApplication::translate("MainWindow", "PKG Viewer", nullptr));