mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-11-10 01:50:25 +01:00
[cheats] add runtime cheats toggles with master code support (#4334)
add per-cheat runtime toggles (thread-safe). add master code handling (master code cannot be disabled, as noted in Atmosphere's implementation). add configurable global / per-game initial states for cheat entries. remove fixed opcode limits and do some fixes to text parsing / file loading. do not run debug log while cheat logging is not enabled, to reduce performance impacts. update the `Using Cheats` document to reflect the changes. - [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). - [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md) - [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. ------------------- Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4334 Reviewed-by: lizzie <lizzie@eden-emu.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-by: John <john@eden-emu.dev>
This commit is contained in:
parent
b4d5760014
commit
69665063a9
24 changed files with 365 additions and 55 deletions
|
|
@ -91,6 +91,14 @@
|
|||
<addaction name="action_Configure"/>
|
||||
<addaction name="action_Configure_Current_Game"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Cheats">
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>&Cheats</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_View">
|
||||
<property name="title">
|
||||
<string>&View</string>
|
||||
|
|
@ -241,6 +249,7 @@
|
|||
</widget>
|
||||
<addaction name="menu_File"/>
|
||||
<addaction name="menu_Emulation"/>
|
||||
<addaction name="menu_Cheats"/>
|
||||
<addaction name="menu_View"/>
|
||||
<addaction name="menu_Tools"/>
|
||||
<addaction name="menu_Multiplayer"/>
|
||||
|
|
|
|||
|
|
@ -78,10 +78,12 @@
|
|||
#include <QGuiApplication>
|
||||
#include <QInputDialog>
|
||||
#include <QMimeData>
|
||||
#include <QMouseEvent>
|
||||
#include <QPalette>
|
||||
#include <QProgressDialog>
|
||||
#include <QScreen>
|
||||
#include <QShortcut>
|
||||
#include <QSignalBlocker>
|
||||
#include <QStatusBar>
|
||||
#include <QtConcurrentRun>
|
||||
|
||||
|
|
@ -134,6 +136,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
|||
#endif
|
||||
|
||||
// Core //
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/general.h"
|
||||
#include "core/frontend/applets/mii_edit.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
|
|
@ -147,6 +150,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
|||
#include "core/file_sys/common_funcs.h"
|
||||
#include "core/file_sys/romfs.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/memory/dmnt_cheat_types.h"
|
||||
|
||||
#include "core/tools/renderdoc.h"
|
||||
|
||||
|
|
@ -1434,6 +1438,9 @@ void MainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
|
|||
}
|
||||
|
||||
void MainWindow::ConnectWidgetEvents() {
|
||||
ui->menu_Cheats->installEventFilter(this);
|
||||
ui->menu_Cheats->menuAction()->setVisible(false);
|
||||
|
||||
connect(game_list, &GameList::BootGame, this, &MainWindow::BootGameFromList);
|
||||
connect(game_list, &GameList::GameChosen, this, &MainWindow::OnGameListLoadFile);
|
||||
connect(game_list, &GameList::OpenDirectory, this, &MainWindow::OnGameListOpenDirectory);
|
||||
|
|
@ -1468,6 +1475,8 @@ void MainWindow::ConnectWidgetEvents() {
|
|||
// Software Keyboard Applet
|
||||
connect(this, &MainWindow::EmulationStarting, this, &MainWindow::SoftwareKeyboardExit);
|
||||
connect(this, &MainWindow::EmulationStopping, this, &MainWindow::SoftwareKeyboardExit);
|
||||
connect(this, &MainWindow::EmulationStarting, this, &MainWindow::RefreshRuntimeCheats);
|
||||
connect(this, &MainWindow::EmulationStopping, this, &MainWindow::ClearRuntimeCheats);
|
||||
|
||||
connect(&status_bar_update_timer, &QTimer::timeout, this, &MainWindow::UpdateStatusBar);
|
||||
|
||||
|
|
@ -1475,6 +1484,68 @@ void MainWindow::ConnectWidgetEvents() {
|
|||
&MultiplayerState::UpdateThemedIcons);
|
||||
}
|
||||
|
||||
void MainWindow::RefreshRuntimeCheats() {
|
||||
ClearRuntimeCheats();
|
||||
|
||||
const auto cheats = QtCommon::system->GetRuntimeCheats();
|
||||
auto* disable_all = ui->menu_Cheats->addAction(tr("Disable All Cheats"));
|
||||
connect(disable_all, &QAction::triggered, this, [this] {
|
||||
for (auto* action : runtime_cheat_actions) {
|
||||
if (action->isEnabled()) {
|
||||
action->setChecked(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
auto* enable_all = ui->menu_Cheats->addAction(tr("Enable All Cheats"));
|
||||
connect(enable_all, &QAction::triggered, this, [this] {
|
||||
for (auto* action : runtime_cheat_actions) {
|
||||
if (action->isEnabled()) {
|
||||
action->setChecked(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui->menu_Cheats->addSeparator();
|
||||
runtime_cheat_actions.reserve(cheats.size());
|
||||
for (const auto& cheat : cheats) {
|
||||
const QString name = cheat.name.empty() ? tr("Unnamed Cheat")
|
||||
: QString::fromUtf8(cheat.name);
|
||||
auto* action = ui->menu_Cheats->addAction(name);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(cheat.enabled || cheat.is_master);
|
||||
action->setEnabled(!cheat.is_master);
|
||||
connect(action, &QAction::toggled, this, [action, id = cheat.id](bool enabled) {
|
||||
if (!QtCommon::system->SetCheatEnabled(id, enabled)) {
|
||||
const QSignalBlocker blocker{action};
|
||||
action->setChecked(!enabled);
|
||||
}
|
||||
});
|
||||
runtime_cheat_actions.push_back(action);
|
||||
}
|
||||
|
||||
ui->menu_Cheats->menuAction()->setVisible(!runtime_cheat_actions.empty());
|
||||
}
|
||||
|
||||
void MainWindow::ClearRuntimeCheats() {
|
||||
ui->menu_Cheats->clear();
|
||||
runtime_cheat_actions.clear();
|
||||
ui->menu_Cheats->menuAction()->setVisible(false);
|
||||
}
|
||||
|
||||
bool MainWindow::eventFilter(QObject* watched, QEvent* event) {
|
||||
if (watched == ui->menu_Cheats && event->type() == QEvent::MouseButtonRelease) {
|
||||
const auto* mouse_event = static_cast<QMouseEvent*>(event);
|
||||
auto* action = ui->menu_Cheats->actionAt(mouse_event->pos());
|
||||
if (mouse_event->button() == Qt::LeftButton && action && action->isEnabled() &&
|
||||
action->isCheckable()) {
|
||||
action->trigger();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QMainWindow::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void MainWindow::ConnectMenuEvents() {
|
||||
const auto connect_menu = [&]<typename Fn>(QAction* action, const Fn& event_fn) {
|
||||
connect(action, &QAction::triggered, this, event_fn);
|
||||
|
|
|
|||
|
|
@ -176,6 +176,9 @@ public:
|
|||
|
||||
std::filesystem::path GetShortcutPath(QtCommon::Game::ShortcutTarget target);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
|
|
@ -264,6 +267,8 @@ private:
|
|||
void ConnectWidgetEvents();
|
||||
void ConnectMenuEvents();
|
||||
void UpdateMenuState();
|
||||
void RefreshRuntimeCheats();
|
||||
void ClearRuntimeCheats();
|
||||
|
||||
void SetupPrepareForSleep();
|
||||
|
||||
|
|
@ -552,6 +557,7 @@ private:
|
|||
QString startup_icon_theme;
|
||||
|
||||
QActionGroup* game_size_actions;
|
||||
std::vector<QAction*> runtime_cheat_actions;
|
||||
|
||||
// Debugger panes
|
||||
ControllerDialog* controller_dialog = nullptr;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue