mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-21 12:04:45 +00:00
Management |save checkbox | shadps4 repository
MENU - Cheats/Patches Management (implementing Patches) save patches checkbox add shadps4 repository
This commit is contained in:
parent
9107c6e8c0
commit
3ac48b2d61
9 changed files with 697 additions and 184 deletions
|
@ -548,6 +548,8 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
|
|||
src/qt_gui/about_dialog.ui
|
||||
src/qt_gui/cheats_patches.cpp
|
||||
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.cpp
|
||||
src/qt_gui/main_window.h
|
||||
|
|
|
@ -40,18 +40,18 @@ CheatsPatches::CheatsPatches(const QString& gameName, const QString& gameSerial,
|
|||
: QWidget(parent), m_gameName(gameName), m_gameSerial(gameSerial), m_gameVersion(gameVersion),
|
||||
m_gameSize(gameSize), m_gameImage(gameImage), manager(new QNetworkAccessManager(this)) {
|
||||
setupUI();
|
||||
resize(700, 400);
|
||||
resize(700, 350);
|
||||
setWindowTitle("Cheats / Patches");
|
||||
}
|
||||
|
||||
CheatsPatches::~CheatsPatches() {}
|
||||
|
||||
QString defaultTextEdit =
|
||||
("Cheat/Patches are experimental. Use with caution.\n"
|
||||
"Select the repository from which you want to download cheats for this game and version and "
|
||||
"click the button. Since we do not develop Cheat/Patches, if you encounter issues or want to "
|
||||
"suggest new ones, please send your feedback to:\n"
|
||||
"link not available yet :D");
|
||||
("Cheat/Patches are experimental. Use with caution.\n\n"
|
||||
"Download the cheats individually by selecting the repository and clicking the download "
|
||||
"button.\nIn the Patch tab you can download all Patches at once, choose which one you want "
|
||||
"to use and save the option.\n\n"
|
||||
"As we do not develop the Cheat/Patches,\nplease report issues related to the cheat author.");
|
||||
|
||||
void CheatsPatches::setupUI() {
|
||||
QString CHEATS_DIR_QString =
|
||||
|
@ -68,7 +68,7 @@ void CheatsPatches::setupUI() {
|
|||
|
||||
QLabel* gameImageLabel = new QLabel();
|
||||
if (!m_gameImage.isNull()) {
|
||||
gameImageLabel->setPixmap(m_gameImage.scaled(300, 300, Qt::KeepAspectRatio));
|
||||
gameImageLabel->setPixmap(m_gameImage.scaled(275, 275, Qt::KeepAspectRatio));
|
||||
} else {
|
||||
gameImageLabel->setText("No Image Available");
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ void CheatsPatches::setupUI() {
|
|||
instructionsTextEdit = new QTextEdit();
|
||||
instructionsTextEdit->setText(defaultTextEdit);
|
||||
instructionsTextEdit->setReadOnly(true);
|
||||
instructionsTextEdit->setFixedHeight(130);
|
||||
instructionsTextEdit->setFixedHeight(170);
|
||||
gameInfoLayout->addWidget(instructionsTextEdit);
|
||||
|
||||
// Create the tab widget
|
||||
|
@ -145,25 +145,20 @@ void CheatsPatches::setupUI() {
|
|||
controlLayout->setAlignment(Qt::AlignLeft);
|
||||
QComboBox* downloadComboBox = new QComboBox();
|
||||
|
||||
auto urlCheat_wolf2022 = "https://wolf2022.ir/trainer/" + NameCheatJson;
|
||||
|
||||
downloadComboBox->addItem("wolf2022", urlCheat_wolf2022);
|
||||
downloadComboBox->addItem("wolf2022", "wolf2022");
|
||||
downloadComboBox->addItem("GoldHEN", "GoldHEN");
|
||||
downloadComboBox->addItem("shadPS4", "shadPS4");
|
||||
|
||||
controlLayout->addWidget(downloadComboBox);
|
||||
|
||||
QPushButton* downloadButton = new QPushButton("Download Cheats");
|
||||
connect(downloadButton, &QPushButton::clicked, [=]() {
|
||||
QString url = downloadComboBox->currentData().toString();
|
||||
if (url == "GoldHEN") {
|
||||
downloadFilesGoldHEN();
|
||||
} else {
|
||||
downloadCheats(url);
|
||||
}
|
||||
QString source = downloadComboBox->currentData().toString();
|
||||
downloadCheats(source, m_gameSerial, m_gameVersion, true);
|
||||
});
|
||||
|
||||
QPushButton* removeCheatButton = new QPushButton("Delete File");
|
||||
connect(removeCheatButton, &QPushButton::clicked, [=]() {
|
||||
QPushButton* deleteCheatButton = new QPushButton("Delete File");
|
||||
connect(deleteCheatButton, &QPushButton::clicked, [=]() {
|
||||
QStringListModel* model = qobject_cast<QStringListModel*>(listView_selectFile->model());
|
||||
if (!model) {
|
||||
return;
|
||||
|
@ -196,7 +191,7 @@ void CheatsPatches::setupUI() {
|
|||
});
|
||||
|
||||
controlLayout->addWidget(downloadButton);
|
||||
controlLayout->addWidget(removeCheatButton);
|
||||
controlLayout->addWidget(deleteCheatButton);
|
||||
|
||||
cheatsLayout->addLayout(controlLayout);
|
||||
cheatsTab->setLayout(cheatsLayout);
|
||||
|
@ -205,6 +200,7 @@ void CheatsPatches::setupUI() {
|
|||
QGroupBox* patchesGroupBox = new QGroupBox();
|
||||
patchesGroupBoxLayout = new QVBoxLayout(patchesGroupBox);
|
||||
patchesGroupBoxLayout->setAlignment(Qt::AlignTop);
|
||||
patchesGroupBox->setLayout(patchesGroupBoxLayout);
|
||||
|
||||
QScrollArea* patchesScrollArea = new QScrollArea();
|
||||
patchesScrollArea->setWidgetResizable(true);
|
||||
|
@ -216,8 +212,13 @@ void CheatsPatches::setupUI() {
|
|||
|
||||
QPushButton* patchesButton = new QPushButton("Download All Available Patches");
|
||||
connect(patchesButton, &QPushButton::clicked, [=]() { downloadPatches(); });
|
||||
|
||||
patchesControlLayout->addWidget(patchesButton);
|
||||
|
||||
QPushButton* saveButton = new QPushButton("Save");
|
||||
connect(saveButton, &QPushButton::clicked, this, &CheatsPatches::onSaveButtonClicked);
|
||||
|
||||
patchesControlLayout->addWidget(saveButton);
|
||||
|
||||
patchesLayout->addLayout(patchesControlLayout);
|
||||
patchesTab->setLayout(patchesLayout);
|
||||
|
||||
|
@ -235,9 +236,167 @@ void CheatsPatches::setupUI() {
|
|||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
void CheatsPatches::downloadFilesGoldHEN() {
|
||||
QString url =
|
||||
"https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/main/json.txt";
|
||||
void CheatsPatches::onSaveButtonClicked() {
|
||||
QString patchDir =
|
||||
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);
|
||||
QNetworkReply* reply = manager->get(request);
|
||||
|
@ -245,93 +404,146 @@ void CheatsPatches::downloadFilesGoldHEN() {
|
|||
connect(reply, &QNetworkReply::finished, [=]() {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray jsonData = reply->readAll();
|
||||
processJsonContent(jsonData);
|
||||
} 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();
|
||||
});
|
||||
bool foundFiles = false;
|
||||
|
||||
connect(reply, &QNetworkReply::errorOccurred, [=](QNetworkReply::NetworkError code) {
|
||||
QMessageBox::warning(this, "Download Error",
|
||||
QString("Error in response: %1").arg(reply->errorString()));
|
||||
});
|
||||
}
|
||||
if (source == "GoldHEN" || source == "shadPS4") {
|
||||
QString textContent(jsonData);
|
||||
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) {
|
||||
bool foundFiles = false;
|
||||
QString textContent(jsonData);
|
||||
QRegularExpression regex(QString("%1_%2[^=]*\.json").arg(m_gameSerial).arg(m_gameVersion));
|
||||
QRegularExpressionMatchIterator matches = regex.globalMatch(textContent);
|
||||
QString baseUrl =
|
||||
"https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/main/json/";
|
||||
if (source == "GoldHEN") {
|
||||
baseUrl = "https://raw.githubusercontent.com/GoldHEN/GoldHEN_Cheat_Repository/"
|
||||
"main/json/";
|
||||
} else {
|
||||
baseUrl = "https://raw.githubusercontent.com/shadps4-emu/ps4_cheats/"
|
||||
"main/CHEATS/";
|
||||
}
|
||||
|
||||
QDir dir(Common::FS::GetUserPath(Common::FS::PathType::CheatsDir));
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
while (matches.hasNext()) {
|
||||
QRegularExpressionMatch match = matches.next();
|
||||
QString fileName = match.captured(0);
|
||||
|
||||
while (matches.hasNext()) {
|
||||
QRegularExpressionMatch match = matches.next();
|
||||
QString fileName = match.captured(0);
|
||||
if (!fileName.isEmpty()) {
|
||||
QString newFileName = fileName;
|
||||
int dotIndex = newFileName.lastIndexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
|
||||
if (!fileName.isEmpty()) {
|
||||
QString newFileName = fileName;
|
||||
int dotIndex = newFileName.lastIndexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
newFileName.insert(dotIndex, "_GoldHEN");
|
||||
if (source == "GoldHEN") {
|
||||
newFileName.insert(dotIndex, "_GoldHEN");
|
||||
} else {
|
||||
newFileName.insert(dotIndex, "_shadPS4");
|
||||
}
|
||||
}
|
||||
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;
|
||||
QString localFilePath = dir.filePath(newFileName);
|
||||
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();
|
||||
});
|
||||
|
||||
// Marks that at least one file was found
|
||||
foundFiles = true;
|
||||
} else {
|
||||
if (showMessageBox) {
|
||||
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();
|
||||
emit downloadFinished();
|
||||
});
|
||||
|
||||
if (!foundFiles) {
|
||||
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.");
|
||||
} 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();
|
||||
}
|
||||
// connect(reply, &QNetworkReply::errorOccurred, [=](QNetworkReply::NetworkError code) {
|
||||
// if (showMessageBox)
|
||||
// QMessageBox::warning(this, "Download Error",
|
||||
// QString("Error in response: %1").arg(reply->errorString()));
|
||||
// });
|
||||
}
|
||||
|
||||
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() {
|
||||
QString url = "https://github.com/GoldHEN/GoldHEN_Patch_Repository/tree/main/"
|
||||
"patches/xml";
|
||||
|
@ -482,7 +639,6 @@ void CheatsPatches::downloadPatches() {
|
|||
}
|
||||
|
||||
void CheatsPatches::createFilesJson() {
|
||||
// Directory where XML files are located
|
||||
QString patchesDir =
|
||||
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string());
|
||||
QDir dir(patchesDir);
|
||||
|
@ -680,7 +836,6 @@ void CheatsPatches::onFileSelected(const QModelIndex& index) {
|
|||
}
|
||||
|
||||
void CheatsPatches::loadCheats(const QString& filePath) {
|
||||
|
||||
QFile file(filePath);
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QByteArray jsonData = file.readAll();
|
||||
|
@ -691,8 +846,8 @@ void CheatsPatches::loadCheats(const QString& filePath) {
|
|||
addCheatsToLayout(modsArray, creditsArray);
|
||||
}
|
||||
}
|
||||
void CheatsPatches::loadPatches(const QString& serial) {
|
||||
|
||||
void CheatsPatches::loadPatches(const QString& serial) {
|
||||
QLayoutItem* item;
|
||||
while ((item = patchesGroupBoxLayout->takeAt(0)) != nullptr) {
|
||||
delete item->widget();
|
||||
|
@ -733,6 +888,7 @@ void CheatsPatches::loadPatches(const QString& serial) {
|
|||
QString patchAuthor;
|
||||
QString patchNote;
|
||||
QJsonArray patchLines;
|
||||
bool isEnabled = false;
|
||||
|
||||
while (!xmlReader.atEnd() && !xmlReader.hasError()) {
|
||||
xmlReader.readNext();
|
||||
|
@ -745,11 +901,15 @@ void CheatsPatches::loadPatches(const QString& serial) {
|
|||
patchName = attributes.value("Name").toString();
|
||||
patchAuthor = attributes.value("Author").toString();
|
||||
patchNote = attributes.value("Note").toString();
|
||||
isEnabled = isEnabled =
|
||||
attributes.value("isEnabled").toString() == QStringLiteral("true");
|
||||
}
|
||||
if (appVer == "mask") {
|
||||
patchName = attributes.value("Name").toString();
|
||||
patchName = attributes.value("Name").toString() + " (any version)";
|
||||
patchAuthor = attributes.value("Author").toString();
|
||||
patchNote = attributes.value("Note").toString();
|
||||
isEnabled = isEnabled =
|
||||
attributes.value("isEnabled").toString() == QStringLiteral("true");
|
||||
}
|
||||
} else if (xmlReader.name() == QStringLiteral("PatchList")) {
|
||||
QJsonArray linesArray;
|
||||
|
@ -772,7 +932,8 @@ void CheatsPatches::loadPatches(const QString& serial) {
|
|||
}
|
||||
|
||||
if (!patchName.isEmpty() && !patchLines.isEmpty()) {
|
||||
addPatchToLayout(patchName, patchAuthor, patchNote, patchLines, serial);
|
||||
addPatchToLayout(patchName, patchAuthor, patchNote, patchLines, serial,
|
||||
isEnabled);
|
||||
patchName.clear();
|
||||
patchAuthor.clear();
|
||||
patchNote.clear();
|
||||
|
@ -786,10 +947,12 @@ void CheatsPatches::loadPatches(const QString& serial) {
|
|||
|
||||
void CheatsPatches::addPatchToLayout(const QString& name, const QString& author,
|
||||
const QString& note, const QJsonArray& linesArray,
|
||||
const QString& serial) {
|
||||
|
||||
const QString& serial, bool isEnabled) {
|
||||
QCheckBox* patchCheckBox = new QCheckBox(name);
|
||||
patchCheckBox->setChecked(
|
||||
isEnabled); // Configura o estado do checkbox com base no valor isEnabled
|
||||
patchesGroupBoxLayout->addWidget(patchCheckBox);
|
||||
|
||||
PatchInfo patchInfo;
|
||||
patchInfo.name = name;
|
||||
patchInfo.author = author;
|
||||
|
@ -798,7 +961,6 @@ void CheatsPatches::addPatchToLayout(const QString& name, const QString& author,
|
|||
patchInfo.serial = serial;
|
||||
m_patchInfos[name] = patchInfo;
|
||||
|
||||
// Hook checkbox hover events
|
||||
patchCheckBox->installEventFilter(this);
|
||||
|
||||
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 valueStr = value.toStdString();
|
||||
|
||||
// Determine if the hint field is present
|
||||
bool isHintPresent = m_cheats[modName].hasHint;
|
||||
|
||||
if (MemoryPatcher::g_eboot_address == 0) {
|
||||
MemoryPatcher::patchInfo addingPatch;
|
||||
addingPatch.modNameStr = modNameStr;
|
||||
|
@ -864,8 +1023,9 @@ void CheatsPatches::applyCheat(const QString& modName, bool enabled) {
|
|||
continue;
|
||||
}
|
||||
|
||||
bool isOffset = !isHintPresent;
|
||||
MemoryPatcher::PatchMemory(modNameStr, offsetStr, valueStr, isOffset, false);
|
||||
// Determine if the hint field is present
|
||||
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 {
|
||||
instructionsTextEdit->setText(defaultTextEdit);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,3 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#ifndef CHEATS_PATCHES_H
|
||||
#define CHEATS_PATCHES_H
|
||||
|
||||
|
@ -31,31 +28,34 @@ public:
|
|||
CheatsPatches(const QString& gameName, const QString& gameSerial, const QString& gameVersion,
|
||||
const QString& gameSize, const QPixmap& gameImage, QWidget* parent = nullptr);
|
||||
~CheatsPatches();
|
||||
void downloadCheats(const QString& source, const QString& m_gameSerial,
|
||||
const QString& m_gameVersion, const bool showMessageBox);
|
||||
void downloadPatches();
|
||||
|
||||
signals:
|
||||
void downloadFinished();
|
||||
|
||||
private:
|
||||
// UI Setup and Event Handlers
|
||||
void setupUI();
|
||||
void downloadFilesGoldHEN();
|
||||
void processJsonContent(const QByteArray& jsonData);
|
||||
void onSaveButtonClicked();
|
||||
QCheckBox* findCheckBoxByName(const QString& name);
|
||||
void onTabChanged(int index);
|
||||
void updateNoteTextEdit(const QString& patchName);
|
||||
|
||||
// Cheat and Patch Management
|
||||
void populateFileListCheats();
|
||||
void onFileSelected(const QModelIndex& index);
|
||||
void createFilesJson();
|
||||
void uncheckAllCheatCheckBoxes();
|
||||
|
||||
void loadCheats(const QString& filePath);
|
||||
void loadPatches(const QString& serial);
|
||||
|
||||
void downloadCheats(const QString& url);
|
||||
void downloadPatches();
|
||||
|
||||
void addCheatsToLayout(const QJsonArray& modsArray, const QJsonArray& creditsArray);
|
||||
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 applyPatch(const QString& patchName, bool enabled);
|
||||
QString convertValueToHex(const QString& type, const QString& valueStr);
|
||||
|
@ -110,4 +110,4 @@ private:
|
|||
QItemSelectionModel* selectionModel;
|
||||
};
|
||||
|
||||
#endif // CHEATS_PATCHES_H
|
||||
#endif // CHEATS_PATCHES_H
|
||||
|
|
287
src/qt_gui/cheats_patches_management.cpp
Normal file
287
src/qt_gui/cheats_patches_management.cpp
Normal 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);
|
||||
}
|
||||
}
|
35
src/qt_gui/cheats_patches_management.h
Normal file
35
src/qt_gui/cheats_patches_management.h
Normal 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
|
|
@ -44,6 +44,11 @@ public:
|
|||
itemID = widget->currentRow() * widget->columnCount() + widget->currentColumn();
|
||||
}
|
||||
|
||||
// Do not show the menu if an item is selected
|
||||
if (itemID == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup menu.
|
||||
QMenu menu(widget);
|
||||
QAction createShortcut("Create Shortcut", widget);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <QtConcurrent>
|
||||
|
||||
#include "about_dialog.h"
|
||||
#include "cheats_patches.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/version.h"
|
||||
#include "core/file_format/pkg.h"
|
||||
|
@ -313,6 +314,21 @@ void MainWindow::CreateConnects() {
|
|||
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.
|
||||
connect(ui->dumpGameListAct, &QAction::triggered, this, [&] {
|
||||
QString filePath = qApp->applicationDirPath().append("/GameList.txt");
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <QScopedPointer>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "cheats_patches_management.h"
|
||||
#include "common/config.h"
|
||||
#include "common/path_util.h"
|
||||
#include "core/file_format/psf.h"
|
||||
|
@ -88,6 +89,8 @@ private:
|
|||
PSF psf;
|
||||
|
||||
std::shared_ptr<GameInfoClass> m_game_info = std::make_shared<GameInfoClass>();
|
||||
// Cheats/Patches Management.
|
||||
QVBoxLayout* patchesRightLayout;
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent* event1) override {
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
QAction* setlistModeGridAct;
|
||||
QAction* setlistElfAct;
|
||||
QAction* gameInstallPathAct;
|
||||
QAction* cheatsManagementAct;
|
||||
QAction* dumpGameListAct;
|
||||
QAction* pkgViewerAct;
|
||||
QAction* aboutAct;
|
||||
|
@ -138,11 +139,12 @@ public:
|
|||
gameInstallPathAct = new QAction(MainWindow);
|
||||
gameInstallPathAct->setObjectName("gameInstallPathAct");
|
||||
gameInstallPathAct->setIcon(QIcon(":images/folder_icon.png"));
|
||||
cheatsManagementAct = new QAction(MainWindow);
|
||||
cheatsManagementAct->setObjectName("cheatsManagementAct");
|
||||
dumpGameListAct = new QAction(MainWindow);
|
||||
dumpGameListAct->setObjectName("dumpGameList");
|
||||
pkgViewerAct = new QAction(MainWindow);
|
||||
pkgViewerAct->setObjectName("pkgViewer");
|
||||
pkgViewerAct->setObjectName("pkgViewer");
|
||||
pkgViewerAct->setIcon(QIcon(":images/file_icon.png"));
|
||||
aboutAct = new QAction(MainWindow);
|
||||
aboutAct->setObjectName("aboutAct");
|
||||
|
@ -295,6 +297,7 @@ public:
|
|||
menuSettings->addAction(configureAct);
|
||||
menuSettings->addAction(gameInstallPathAct);
|
||||
menuSettings->addAction(menuUtils->menuAction());
|
||||
menuUtils->addAction(cheatsManagementAct);
|
||||
menuUtils->addAction(dumpGameListAct);
|
||||
menuUtils->addAction(pkgViewerAct);
|
||||
menuAbout->addAction(aboutAct);
|
||||
|
@ -341,6 +344,8 @@ public:
|
|||
setlistElfAct->setText(QCoreApplication::translate("MainWindow", "Elf Viewer", nullptr));
|
||||
gameInstallPathAct->setText(
|
||||
QCoreApplication::translate("MainWindow", "Game Install Directory", nullptr));
|
||||
cheatsManagementAct->setText(
|
||||
QCoreApplication::translate("MainWindow", "Cheats Management", nullptr));
|
||||
dumpGameListAct->setText(
|
||||
QCoreApplication::translate("MainWindow", "Dump Game List", nullptr));
|
||||
pkgViewerAct->setText(QCoreApplication::translate("MainWindow", "PKG Viewer", nullptr));
|
||||
|
|
Loading…
Add table
Reference in a new issue