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
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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));
|
||||||
|
|
Loading…
Reference in New Issue