mirror of
https://github.com/Rosalie241/RMG.git
synced 2026-11-13 17:48:43 +01:00
RMG: implement netplay cheat support
This commit is contained in:
1 parent
d468794979
commit
8e02a0ecda
10 files changed
+512
-34
No files matched your search
@@ -51,6 +51,7 @@ set(RMG_SOURCES
|
||||
UserInterface/Widget/KeybindButton.cpp
|
||||
UserInterface/Dialog/SettingsDialog.cpp
|
||||
UserInterface/Dialog/SettingsDialog.ui
|
||||
UserInterface/Dialog/Cheats/CheatsCommon.cpp
|
||||
UserInterface/Dialog/Cheats/CheatsDialog.cpp
|
||||
UserInterface/Dialog/Cheats/CheatsDialog.ui
|
||||
UserInterface/Dialog/Cheats/AddCheatDialog.cpp
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "CheatsCommon.hpp"
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <RMG-Core/Core.hpp>
|
||||
|
||||
using namespace CheatsCommon;
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
//
|
||||
|
||||
static int find_json_cheat(const QJsonArray& json, const CoreCheat& cheat)
|
||||
{
|
||||
QJsonObject cheatObject;
|
||||
QString targetCheatName = QString::fromStdString(cheat.Name);
|
||||
|
||||
for (qsizetype i = 0; i < json.size(); i++)
|
||||
{
|
||||
cheatObject = json[i].toObject();
|
||||
|
||||
if (cheatObject["name"].toString() == targetCheatName)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Exported Function
|
||||
//
|
||||
|
||||
bool CheatsCommon::IsCheatEnabled(bool netplay, const QJsonArray& json, const CoreCheat& cheat)
|
||||
{
|
||||
if (netplay)
|
||||
{
|
||||
int index = find_json_cheat(json, cheat);
|
||||
return index != -1 && json[index].toObject().contains("codes");
|
||||
}
|
||||
else
|
||||
{
|
||||
return CoreIsCheatEnabled(cheat);
|
||||
}
|
||||
}
|
||||
|
||||
bool CheatsCommon::EnableCheat(bool netplay, QJsonArray& json, const CoreCheat& cheat, bool enabled)
|
||||
{
|
||||
if (netplay)
|
||||
{
|
||||
QJsonObject cheatObject;
|
||||
QJsonArray codesArray;
|
||||
QString targetCheatName = QString::fromStdString(cheat.Name);
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
for (const auto& cheatCode : cheat.CheatCodes)
|
||||
{
|
||||
QJsonObject codeObject;
|
||||
codeObject["address"] = (qint64)cheatCode.Address;
|
||||
codeObject["value"] = (qint64)cheatCode.Value;
|
||||
codeObject["use_option"] = cheatCode.UseOptions;
|
||||
codeObject["option_index"] = cheatCode.OptionIndex;
|
||||
codeObject["option_size"] = cheatCode.OptionSize;
|
||||
codesArray.push_back(codeObject);
|
||||
}
|
||||
|
||||
cheatObject["name"] = targetCheatName;
|
||||
cheatObject["codes"] = codesArray;
|
||||
cheatObject["has_options"] = cheat.HasOptions;
|
||||
|
||||
int index = find_json_cheat(json, cheat);
|
||||
if (index != -1)
|
||||
{
|
||||
// copy over the option object
|
||||
cheatObject["option"] = json[index].toObject().value("option").toObject();
|
||||
json[index] = cheatObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
json.push_back(cheatObject);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = find_json_cheat(json, cheat);
|
||||
if (index != -1)
|
||||
{
|
||||
cheatObject = json[index].toObject();
|
||||
|
||||
// if cheat object has an option key
|
||||
// we have to keep that key because
|
||||
// else the UI will behave inconsistent
|
||||
// with the non-netplay cheats dialog
|
||||
if (cheatObject.contains("option"))
|
||||
{
|
||||
cheatObject.remove("codes");
|
||||
json[index] = cheatObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
json.removeAt(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CoreEnableCheat(cheat, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
bool CheatsCommon::HasCheatOptionSet(bool netplay, const QJsonArray& json, const CoreCheat& cheat)
|
||||
{
|
||||
if (netplay)
|
||||
{
|
||||
int index = find_json_cheat(json, cheat);
|
||||
return index != -1 && json[index].toObject().contains("option");
|
||||
}
|
||||
else
|
||||
{
|
||||
return CoreHasCheatOptionSet(cheat);
|
||||
}
|
||||
}
|
||||
|
||||
bool CheatsCommon::GetCheatOption(bool netplay, const QJsonArray& json, const CoreCheat& cheat, CoreCheatOption& option)
|
||||
{
|
||||
if (netplay)
|
||||
{
|
||||
QJsonObject cheatObject;
|
||||
QJsonObject optionObject;
|
||||
|
||||
int index = find_json_cheat(json, cheat);
|
||||
if (index == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
cheatObject = json[index].toObject();
|
||||
optionObject = cheatObject["option"].toObject();
|
||||
option.Name = optionObject["name"].toString().toStdString();
|
||||
option.Size = optionObject["size"].toInt();
|
||||
option.Value = optionObject["value"].toInteger();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CoreGetCheatOption(cheat, option);
|
||||
}
|
||||
}
|
||||
bool CheatsCommon::SetCheatOption(bool netplay, QJsonArray& json, const CoreCheat& cheat, CoreCheatOption& option)
|
||||
{
|
||||
if (netplay)
|
||||
{
|
||||
QJsonObject cheatObject;
|
||||
QJsonObject optionObject;
|
||||
QString targetCheatName = QString::fromStdString(cheat.Name);
|
||||
|
||||
int index = find_json_cheat(json, cheat);
|
||||
if (index != -1)
|
||||
{
|
||||
cheatObject = json[index].toObject();
|
||||
optionObject["name"] = QString::fromStdString(option.Name);
|
||||
optionObject["size"] = option.Size;
|
||||
optionObject["value"] = (qint64)option.Value;
|
||||
|
||||
cheatObject["option"] = optionObject;
|
||||
|
||||
json[index] = cheatObject;
|
||||
}
|
||||
else
|
||||
{ // create dummy object when option has been set
|
||||
// without the user having the cheat enabled
|
||||
optionObject["name"] = QString::fromStdString(option.Name);
|
||||
optionObject["size"] = option.Size;
|
||||
optionObject["value"] = (qint64)option.Value;
|
||||
|
||||
cheatObject["name"] = targetCheatName;
|
||||
cheatObject["option"] = optionObject;
|
||||
|
||||
json.append(cheatObject);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CoreGetCheatOption(cheat, option);
|
||||
}
|
||||
}
|
||||
|
||||
bool CheatsCommon::ParseCheatJson(const QJsonArray& json, std::vector<CoreCheat>& cheats)
|
||||
{
|
||||
QJsonObject cheatObject;
|
||||
QJsonArray cheatCodesArray;
|
||||
QJsonObject cheatCodeObject;
|
||||
QJsonObject cheatOptionObject;
|
||||
CoreCheat cheat;
|
||||
CoreCheatCode cheatCode;
|
||||
CoreCheatOption cheatOption;
|
||||
bool skipCheat = false;
|
||||
|
||||
for (qsizetype i = 0; i < json.size(); i++)
|
||||
{
|
||||
cheatObject = json[i].toObject();
|
||||
|
||||
if (!cheatObject.contains("name") ||
|
||||
!cheatObject.contains("codes") ||
|
||||
!cheatObject.contains("has_options"))
|
||||
{ // skip disabled cheats
|
||||
continue;
|
||||
}
|
||||
|
||||
// reset cheat
|
||||
cheat = {};
|
||||
skipCheat = false;
|
||||
|
||||
cheat.Name = cheatObject["name"].toString().toStdString();
|
||||
cheat.HasOptions = cheatObject["has_options"].toBool();
|
||||
|
||||
if (cheat.Name.empty())
|
||||
{ // name validation
|
||||
continue;
|
||||
}
|
||||
|
||||
// parse cheat codes
|
||||
cheatCodesArray = cheatObject["codes"].toArray();
|
||||
for (qsizetype x = 0; x < cheatCodesArray.size(); x++)
|
||||
{
|
||||
cheatCodeObject = cheatCodesArray[x].toObject();
|
||||
|
||||
// ensure json object contains required keys
|
||||
if (!cheatCodeObject.contains("address") ||
|
||||
!cheatCodeObject.contains("value") ||
|
||||
!cheatCodeObject.contains("use_option") ||
|
||||
!cheatCodeObject.contains("option_index") ||
|
||||
!cheatCodeObject.contains("option_size"))
|
||||
{
|
||||
skipCheat = true;
|
||||
break;
|
||||
}
|
||||
|
||||
cheatCode.Address = (uint32_t)cheatCodeObject["address"].toInteger();
|
||||
cheatCode.Value = cheatCodeObject["value"].toInt();
|
||||
cheatCode.UseOptions = cheatCodeObject["use_option"].toBool();
|
||||
cheatCode.OptionIndex = cheatCodeObject["option_index"].toInt();
|
||||
cheatCode.OptionSize = cheatCodeObject["option_size"].toInt();
|
||||
|
||||
cheat.CheatCodes.push_back(cheatCode);
|
||||
}
|
||||
|
||||
// parse (optional) cheat option
|
||||
if (cheatObject.contains("option"))
|
||||
{
|
||||
cheatOptionObject = cheatObject["option"].toObject();
|
||||
|
||||
// ensure json object has required keys
|
||||
if (!cheatOptionObject.contains("name") ||
|
||||
!cheatOptionObject.contains("size") ||
|
||||
!cheatOptionObject.contains("value"))
|
||||
{
|
||||
skipCheat = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cheatOption.Name = cheatOptionObject["name"].toString().toStdString();
|
||||
cheatOption.Size = cheatOptionObject["size"].toInt();
|
||||
cheatOption.Value = (uint32_t)cheatOptionObject["value"].toInteger();
|
||||
cheat.CheatOptions.push_back(cheatOption);
|
||||
}
|
||||
}
|
||||
|
||||
if (skipCheat)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CHEATSCOMMONH_HPP
|
||||
#define CHEATSCOMMONH_HPP
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QString>
|
||||
|
||||
#include <RMG-Core/Core.hpp>
|
||||
|
||||
namespace CheatsCommon
|
||||
{
|
||||
// Checks whether cheat is enabled
|
||||
bool IsCheatEnabled(bool netplay, const QJsonArray& json, const CoreCheat& cheat);
|
||||
|
||||
// Enables Cheat
|
||||
bool EnableCheat(bool netplay, QJsonArray& json, const CoreCheat& cheat, bool enabled);
|
||||
|
||||
// Returns whether cheat has option set
|
||||
bool HasCheatOptionSet(bool netplay, const QJsonArray& json, const CoreCheat& cheat);
|
||||
|
||||
// Retrieves cheat option
|
||||
bool GetCheatOption(bool netplay, const QJsonArray& json, const CoreCheat& cheat, CoreCheatOption& option);
|
||||
|
||||
// Sets cheat option
|
||||
bool SetCheatOption(bool netplay, QJsonArray& json, const CoreCheat& cheat, CoreCheatOption& option);
|
||||
|
||||
// Parses json into cheat list
|
||||
bool ParseCheatJson(const QJsonArray& json, std::vector<CoreCheat>& cheats);
|
||||
}
|
||||
|
||||
#endif // CHEATSCOMMONH_HPP
|
||||
@@ -11,9 +11,10 @@
|
||||
|
||||
#include "AddCheatDialog.hpp"
|
||||
#include "ChooseCheatOptionDialog.hpp"
|
||||
|
||||
#include "Utilities/QtMessageBox.hpp"
|
||||
#include "CheatsCommon.hpp"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <RMG-Core/Core.hpp>
|
||||
@@ -23,10 +24,13 @@ Q_DECLARE_METATYPE(CoreCheat);
|
||||
using namespace UserInterface::Dialog;
|
||||
using namespace Utilities;
|
||||
|
||||
CheatsDialog::CheatsDialog(QWidget *parent) : QDialog(parent)
|
||||
CheatsDialog::CheatsDialog(QWidget *parent, bool netplay, QJsonArray cheatsJson) : QDialog(parent)
|
||||
{
|
||||
qRegisterMetaType<CoreCheat>();
|
||||
|
||||
this->netplay = netplay;
|
||||
this->cheatsJson = cheatsJson;
|
||||
|
||||
this->setupUi(this);
|
||||
this->loadCheats();
|
||||
}
|
||||
@@ -40,6 +44,11 @@ bool CheatsDialog::HasFailed(void)
|
||||
return this->failedToParseCheats;
|
||||
}
|
||||
|
||||
QJsonArray CheatsDialog::GetJson(void)
|
||||
{
|
||||
return this->cheatsJson;
|
||||
}
|
||||
|
||||
void CheatsDialog::loadCheats(void)
|
||||
{
|
||||
std::vector<CoreCheat> cheats;
|
||||
@@ -59,7 +68,7 @@ void CheatsDialog::loadCheats(void)
|
||||
QString name = QString::fromStdString(cheat.Name);
|
||||
QString section;
|
||||
QStringList sections = name.split("\\");
|
||||
bool enabled = CoreIsCheatEnabled(cheat);
|
||||
bool enabled = CheatsCommon::IsCheatEnabled(this->netplay, this->cheatsJson, cheat);
|
||||
|
||||
for (int i = 0; i < sections.size(); i++)
|
||||
{
|
||||
@@ -173,7 +182,8 @@ QString CheatsDialog::getTreeWidgetItemTextFromCheat(CoreCheat cheat)
|
||||
if (cheat.HasOptions)
|
||||
{
|
||||
CoreCheatOption cheatOption;
|
||||
if (!CoreHasCheatOptionSet(cheat) || !CoreGetCheatOption(cheat, cheatOption))
|
||||
if (!CheatsCommon::HasCheatOptionSet(this->netplay, this->cheatsJson, cheat) ||
|
||||
!CheatsCommon::GetCheatOption(this->netplay, this->cheatsJson, cheat, cheatOption))
|
||||
{
|
||||
text = cheatName + " (=> ???? - Not Set)";
|
||||
}
|
||||
@@ -203,7 +213,7 @@ void CheatsDialog::on_cheatsTreeWidget_itemChanged(QTreeWidgetItem *item, int co
|
||||
CoreCheat cheat = item->data(column, Qt::UserRole).value<CoreCheat>();
|
||||
bool enabled = (item->checkState(column) == Qt::CheckState::Checked);
|
||||
|
||||
if (enabled && cheat.HasOptions && !CoreHasCheatOptionSet(cheat))
|
||||
if (enabled && cheat.HasOptions && !CheatsCommon::HasCheatOptionSet(this->netplay, this->cheatsJson, cheat))
|
||||
{
|
||||
// ask user to select an option
|
||||
this->on_cheatsTreeWidget_itemDoubleClicked(item, column);
|
||||
@@ -211,14 +221,14 @@ void CheatsDialog::on_cheatsTreeWidget_itemChanged(QTreeWidgetItem *item, int co
|
||||
// make sure the user selected an option,
|
||||
// if they did then enable the cheat as requested,
|
||||
// if not, reset the checkbox
|
||||
if (!CoreHasCheatOptionSet(cheat))
|
||||
if (!CheatsCommon::HasCheatOptionSet(this->netplay, this->cheatsJson, cheat))
|
||||
{
|
||||
item->setCheckState(0, Qt::CheckState::Unchecked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CoreEnableCheat(cheat, enabled);
|
||||
CheatsCommon::EnableCheat(this->netplay, this->cheatsJson, cheat, enabled);
|
||||
}
|
||||
|
||||
void CheatsDialog::on_cheatsTreeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
|
||||
@@ -251,9 +261,12 @@ void CheatsDialog::on_cheatsTreeWidget_itemDoubleClicked(QTreeWidgetItem *item,
|
||||
return;
|
||||
}
|
||||
|
||||
Dialog::ChooseCheatOptionDialog dialog(cheat, this);
|
||||
Dialog::ChooseCheatOptionDialog dialog(cheat, this->netplay, this->cheatsJson, this);
|
||||
dialog.exec();
|
||||
|
||||
// update json
|
||||
this->cheatsJson = dialog.GetJson();
|
||||
|
||||
// re-load cheat options
|
||||
item->setText(column, this->getTreeWidgetItemTextFromCheat(cheat));
|
||||
}
|
||||
@@ -312,6 +325,12 @@ void CheatsDialog::on_removeCheatButton_clicked(void)
|
||||
|
||||
void CheatsDialog::accept(void)
|
||||
{
|
||||
if (this->netplay)
|
||||
{
|
||||
QDialog::accept();
|
||||
return;
|
||||
}
|
||||
|
||||
CoreSettingsSave();
|
||||
|
||||
if (!CoreApplyCheats())
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
#ifndef CHEATSDIALOG_HPP
|
||||
#define CHEATSDIALOG_HPP
|
||||
|
||||
#include <QWidget>
|
||||
#include <QJsonArray>
|
||||
#include <QDialog>
|
||||
#include <QWidget>
|
||||
|
||||
#include <RMG-Core/Core.hpp>
|
||||
|
||||
@@ -26,14 +27,18 @@ class CheatsDialog : public QDialog, private Ui::CheatsDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheatsDialog(QWidget *parent);
|
||||
CheatsDialog(QWidget *parent, bool netplay = false, QJsonArray cheatsJson = {});
|
||||
~CheatsDialog(void);
|
||||
|
||||
bool HasFailed(void);
|
||||
QJsonArray GetJson(void);
|
||||
|
||||
|
||||
private:
|
||||
bool needCloseRom = false;
|
||||
bool failedToParseCheats = false;
|
||||
bool netplay = false;
|
||||
QJsonArray cheatsJson;
|
||||
|
||||
void loadCheats(void);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "ChooseCheatOptionDialog.hpp"
|
||||
#include "CheatsCommon.hpp"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
@@ -17,17 +18,19 @@ Q_DECLARE_METATYPE(CoreCheatOption);
|
||||
|
||||
using namespace UserInterface::Dialog;
|
||||
|
||||
ChooseCheatOptionDialog::ChooseCheatOptionDialog(CoreCheat cheat, QWidget *parent) : QDialog(parent)
|
||||
ChooseCheatOptionDialog::ChooseCheatOptionDialog(CoreCheat cheat, bool netplay, QJsonArray cheatsJson, QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
qRegisterMetaType<CoreCheatOption>();
|
||||
|
||||
this->setupUi(this);
|
||||
this->cheat = cheat;
|
||||
|
||||
this->netplay = netplay;
|
||||
this->cheatsJson = cheatsJson;
|
||||
|
||||
CoreCheatOption setCheatOption;
|
||||
|
||||
bool checkCheatOption = CoreHasCheatOptionSet(cheat) &&
|
||||
CoreGetCheatOption(cheat, setCheatOption);
|
||||
bool checkCheatOption = CheatsCommon::HasCheatOptionSet(this->netplay, this->cheatsJson, cheat) &&
|
||||
CheatsCommon::GetCheatOption(this->netplay, this->cheatsJson, cheat, setCheatOption);
|
||||
|
||||
for (CoreCheatOption& option : cheat.CheatOptions)
|
||||
{
|
||||
@@ -49,7 +52,11 @@ ChooseCheatOptionDialog::ChooseCheatOptionDialog(CoreCheat cheat, QWidget *paren
|
||||
|
||||
ChooseCheatOptionDialog::~ChooseCheatOptionDialog()
|
||||
{
|
||||
}
|
||||
|
||||
QJsonArray ChooseCheatOptionDialog::GetJson(void)
|
||||
{
|
||||
return this->cheatsJson;
|
||||
}
|
||||
|
||||
void ChooseCheatOptionDialog::on_cheatOptionsTreeWidget_itemChanged(QTreeWidgetItem *item, int column)
|
||||
@@ -70,17 +77,8 @@ void ChooseCheatOptionDialog::on_cheatOptionsTreeWidget_itemChanged(QTreeWidgetI
|
||||
}
|
||||
}
|
||||
|
||||
void ChooseCheatOptionDialog::on_buttonBox_clicked(QAbstractButton *button)
|
||||
void ChooseCheatOptionDialog::accept(void)
|
||||
{
|
||||
QPushButton *pushButton = (QPushButton *)button;
|
||||
QPushButton *okButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
|
||||
// do nothing when the user didn't press ok
|
||||
if (pushButton != okButton)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this->cheatOptionsTreeWidget->topLevelItemCount(); i++)
|
||||
{
|
||||
QTreeWidgetItem* item = this->cheatOptionsTreeWidget->topLevelItem(i);
|
||||
@@ -88,8 +86,9 @@ void ChooseCheatOptionDialog::on_buttonBox_clicked(QAbstractButton *button)
|
||||
if (item->checkState(0) == Qt::CheckState::Checked)
|
||||
{
|
||||
CoreCheatOption cheatOption = item->data(0, Qt::UserRole).value<CoreCheatOption>();
|
||||
CoreSetCheatOption(this->cheat, cheatOption);
|
||||
return;
|
||||
CheatsCommon::SetCheatOption(this->netplay, this->cheatsJson, this->cheat, cheatOption);
|
||||
}
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
@@ -10,8 +10,9 @@
|
||||
#ifndef CHOOSECHEATOPTIONDIALOG_HPP
|
||||
#define CHOOSECHEATOPTIONDIALOG_HPP
|
||||
|
||||
#include <QWidget>
|
||||
#include <QJsonArray>
|
||||
#include <QDialog>
|
||||
#include <QWidget>
|
||||
|
||||
#include <RMG-Core/Core.hpp>
|
||||
|
||||
@@ -27,14 +28,18 @@ class ChooseCheatOptionDialog : public QDialog, private Ui::ChooseCheatOptionDia
|
||||
|
||||
private:
|
||||
CoreCheat cheat;
|
||||
bool netplay;
|
||||
QJsonArray cheatsJson;
|
||||
|
||||
public:
|
||||
ChooseCheatOptionDialog(CoreCheat cheat, QWidget *parent);
|
||||
ChooseCheatOptionDialog(CoreCheat cheat, bool netplay, QJsonArray cheatsJson, QWidget *parent);
|
||||
~ChooseCheatOptionDialog(void);
|
||||
|
||||
QJsonArray GetJson(void);
|
||||
|
||||
private slots:
|
||||
void on_cheatOptionsTreeWidget_itemChanged(QTreeWidgetItem *item, int column);
|
||||
void on_buttonBox_clicked(QAbstractButton *button);
|
||||
void accept(void) Q_DECL_OVERRIDE;
|
||||
};
|
||||
} // namespace Dialog
|
||||
} // namespace UserInterface
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "UserInterface/Dialog/Cheats/CheatsCommon.hpp"
|
||||
#include "UserInterface/Dialog/Cheats/CheatsDialog.hpp"
|
||||
#include "Utilities/QtMessageBox.hpp"
|
||||
#include "NetplaySessionDialog.hpp"
|
||||
#include "NetplayCommon.hpp"
|
||||
#include "Utilities/QtMessageBox.hpp"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QPushButton>
|
||||
@@ -31,6 +33,7 @@ NetplaySessionDialog::NetplaySessionDialog(QWidget *parent, QWebSocket* webSocke
|
||||
|
||||
QJsonObject session = json.value("room").toObject();
|
||||
|
||||
this->sessionJson = json.value("room").toObject();
|
||||
this->nickName = json.value("player_name").toString();
|
||||
this->sessionPort = session.value("port").toInt();
|
||||
this->sessionName = session.value("room_name").toString();
|
||||
@@ -62,6 +65,10 @@ NetplaySessionDialog::NetplaySessionDialog(QWidget *parent, QWebSocket* webSocke
|
||||
QPushButton* startButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
startButton->setText("Start");
|
||||
startButton->setEnabled(false);
|
||||
|
||||
QPushButton* cheatsButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
cheatsButton->setText("Cheats");
|
||||
cheatsButton->setIcon(QIcon());
|
||||
}
|
||||
|
||||
NetplaySessionDialog::~NetplaySessionDialog(void)
|
||||
@@ -72,6 +79,35 @@ NetplaySessionDialog::~NetplaySessionDialog(void)
|
||||
}
|
||||
}
|
||||
|
||||
bool NetplaySessionDialog::applyCheats(void)
|
||||
{
|
||||
QJsonObject session = this->sessionJson;
|
||||
QJsonObject features = session.value("features").toObject();
|
||||
QString cheatJson = features["cheats"].toString();
|
||||
|
||||
if (!cheatJson.isEmpty())
|
||||
{
|
||||
QJsonDocument cheatDocument = QJsonDocument::fromJson(cheatJson.toUtf8());
|
||||
QJsonArray cheatArray = cheatDocument.array();
|
||||
std::vector<CoreCheat> cheats;
|
||||
|
||||
if (!CheatsCommon::ParseCheatJson(cheatArray, cheats))
|
||||
{
|
||||
QString error = "Failed to parse cheats json: " + QString(cheatDocument.toJson());
|
||||
QtMessageBox::Error(this, "CheatsCommon::ParseCheatJson() Failed", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CoreSetNetplayCheats(cheats))
|
||||
{
|
||||
QtMessageBox::Error(this, "CoreSetNetplayCheats() Failed", QString::fromStdString(CoreGetError()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetplaySessionDialog::on_webSocket_textMessageReceived(QString message)
|
||||
{
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(message.toUtf8());
|
||||
@@ -91,14 +127,17 @@ void NetplaySessionDialog::on_webSocket_textMessageReceived(QString message)
|
||||
this->listWidget->addItem(name);
|
||||
if (!name.isEmpty())
|
||||
{
|
||||
if (this->nickName == name)
|
||||
bool nameMatch = this->nickName == name;
|
||||
if (nameMatch)
|
||||
{
|
||||
this->sessionNumber = i + 1;
|
||||
}
|
||||
if (!this->started && i == 0)
|
||||
{
|
||||
QPushButton* startButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
startButton->setEnabled(this->nickName == name);
|
||||
QPushButton* cheatsButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
startButton->setEnabled(nameMatch);
|
||||
cheatsButton->setEnabled(nameMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,10 +152,17 @@ void NetplaySessionDialog::on_webSocket_textMessageReceived(QString message)
|
||||
if (json.value("accept").toInt() == 0)
|
||||
{
|
||||
this->started = true;
|
||||
this->applyCheats();
|
||||
emit OnPlayGame(this->sessionFile, this->webSocket->peerAddress().toString(), this->sessionPort, this->sessionNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
// allow user to try again
|
||||
QPushButton* startButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
QPushButton* cheatsButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
startButton->setEnabled(true);
|
||||
cheatsButton->setEnabled(true);
|
||||
|
||||
QtMessageBox::Error(this, "Server Error", json.value("message").toString());
|
||||
}
|
||||
}
|
||||
@@ -126,6 +172,17 @@ void NetplaySessionDialog::on_webSocket_textMessageReceived(QString message)
|
||||
this->chatPlainTextEdit->appendHtml(message);
|
||||
this->chatPlainTextEdit->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
}
|
||||
else if (type == "reply_edit_room")
|
||||
{
|
||||
if (json.value("accept").toInt() == 0)
|
||||
{
|
||||
this->sessionJson = json.value("room").toObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
QtMessageBox::Error(this, "Server Error", json.value("message").toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionDialog::on_chatLineEdit_textChanged(QString text)
|
||||
@@ -149,10 +206,65 @@ void NetplaySessionDialog::on_sendPushButton_clicked(void)
|
||||
this->chatLineEdit->clear();
|
||||
}
|
||||
|
||||
void NetplaySessionDialog::on_buttonBox_clicked(QAbstractButton* button)
|
||||
{
|
||||
QPushButton* pushButton = (QPushButton*)button;
|
||||
QPushButton* cheatsButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
|
||||
if (pushButton == cheatsButton)
|
||||
{
|
||||
QString cheatsJson = this->sessionJson.value("features").toObject().value("cheats").toString();
|
||||
QJsonDocument cheatsDocument = QJsonDocument::fromJson(cheatsJson.toUtf8());
|
||||
|
||||
if (!CoreOpenRom(this->sessionFile.toStdString()))
|
||||
{
|
||||
QtMessageBox::Error(this, "CoreOpenRom() Failed", QString::fromStdString(CoreGetError()));
|
||||
return;
|
||||
}
|
||||
|
||||
Dialog::CheatsDialog dialog(this, true, cheatsDocument.array());
|
||||
dialog.exec();
|
||||
|
||||
if (!CoreCloseRom())
|
||||
{
|
||||
QtMessageBox::Error(this, "CoreCloseRom() Failed", QString::fromStdString(CoreGetError()));
|
||||
return;
|
||||
}
|
||||
|
||||
// request an update to the existing session with the new cheats
|
||||
cheatsDocument.setArray(dialog.GetJson());
|
||||
QJsonObject session = this->sessionJson;
|
||||
QJsonObject features = session.value("features").toObject();
|
||||
if (!cheatsDocument.array().empty())
|
||||
{ // only add cheats object when it's not empty
|
||||
features["cheats"] = QString(cheatsDocument.toJson(QJsonDocument::Compact));
|
||||
}
|
||||
else
|
||||
{ // else remove it
|
||||
features.remove("cheats");
|
||||
}
|
||||
session.insert("features", features);
|
||||
|
||||
// only request update when needed
|
||||
if (this->sessionJson != session)
|
||||
{
|
||||
QJsonObject json;
|
||||
json.insert("type", "request_edit_room");
|
||||
json.insert("player_name", this->nickName);
|
||||
json.insert("room", session);
|
||||
NetplayCommon::AddCommonJson(json);
|
||||
|
||||
this->webSocket->sendTextMessage(QJsonDocument(json).toJson());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetplaySessionDialog::accept()
|
||||
{
|
||||
QPushButton* startButton = this->buttonBox->button(QDialogButtonBox::Ok);
|
||||
QPushButton* cheatsButton = this->buttonBox->button(QDialogButtonBox::RestoreDefaults);
|
||||
startButton->setEnabled(false);
|
||||
cheatsButton->setEnabled(false);
|
||||
|
||||
QJsonObject json;
|
||||
QJsonObject session;
|
||||
|
||||
@@ -33,18 +33,22 @@ class NetplaySessionDialog : public QDialog, private Ui::NetplaySessionDialog
|
||||
QString sessionFile;
|
||||
QString nickName;
|
||||
QString sessionName;
|
||||
QJsonObject sessionJson;
|
||||
int sessionPort = -1;
|
||||
int sessionNumber = -1;
|
||||
bool started = false;
|
||||
|
||||
QWebSocket* webSocket;
|
||||
|
||||
bool applyCheats(void);
|
||||
|
||||
private slots:
|
||||
void on_webSocket_textMessageReceived(QString message);
|
||||
|
||||
void on_chatLineEdit_textChanged(QString text);
|
||||
void on_sendPushButton_clicked(void);
|
||||
|
||||
void on_buttonBox_clicked(QAbstractButton* button);
|
||||
|
||||
void accept(void) Q_DECL_OVERRIDE;
|
||||
void reject(void) Q_DECL_OVERRIDE;
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok|QDialogButtonBox::StandardButton::RestoreDefaults</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>false</bool>
|
||||
|
||||
Reference in new issue
Block a user