diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/cheats/model/CheatEngine.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/cheats/model/CheatEngine.kt index 8cd10678b2..2fef03bebf 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/cheats/model/CheatEngine.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/cheats/model/CheatEngine.kt @@ -7,25 +7,13 @@ package org.citra.citra_emu.features.cheats.model import androidx.annotation.Keep @Keep -class CheatEngine(titleId: Long) { - @Keep - private val mPointer: Long - - init { - mPointer = initialize(titleId) - } - - protected external fun finalize() +object CheatEngine { + external fun loadCheatFile(titleId: Long) + external fun saveCheatFile(titleId: Long) external fun getCheats(): Array external fun addCheat(cheat: Cheat?) external fun removeCheat(index: Int) external fun updateCheat(index: Int, newCheat: Cheat?) - external fun saveCheatFile() - - companion object { - @JvmStatic - private external fun initialize(titleId: Long): Long - } } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/cheats/model/CheatsViewModel.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/cheats/model/CheatsViewModel.kt index 48786ad82c..e794fe588a 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/cheats/model/CheatsViewModel.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/cheats/model/CheatsViewModel.kt @@ -47,18 +47,19 @@ class CheatsViewModel : ViewModel() { val detailsViewFocusChange get() = _detailsViewFocusChange.asStateFlow() private val _detailsViewFocusChange = MutableStateFlow(false) - private var cheatEngine: CheatEngine? = null + private var titleId: Long = 0 lateinit var cheats: Array private var cheatsNeedSaving = false private var selectedCheatPosition = -1 - fun initialize(titleId: Long) { - cheatEngine = CheatEngine(titleId) + fun initialize(titleId_: Long) { + titleId = titleId_; load() } private fun load() { - cheats = cheatEngine!!.getCheats() + CheatEngine.loadCheatFile(titleId) + cheats = CheatEngine.getCheats() for (i in cheats.indices) { cheats[i].setEnabledChangedCallback { cheatsNeedSaving = true @@ -69,7 +70,7 @@ class CheatsViewModel : ViewModel() { fun saveIfNeeded() { if (cheatsNeedSaving) { - cheatEngine!!.saveCheatFile() + CheatEngine.saveCheatFile(titleId) cheatsNeedSaving = false } } @@ -107,7 +108,7 @@ class CheatsViewModel : ViewModel() { _isAdding.value = false _isEditing.value = false val position = cheats.size - cheatEngine!!.addCheat(cheat) + CheatEngine.addCheat(cheat) cheatsNeedSaving = true load() notifyCheatAdded(position) @@ -123,7 +124,7 @@ class CheatsViewModel : ViewModel() { } fun updateSelectedCheat(newCheat: Cheat?) { - cheatEngine!!.updateCheat(selectedCheatPosition, newCheat) + CheatEngine.updateCheat(selectedCheatPosition, newCheat) cheatsNeedSaving = true load() notifyCheatUpdated(selectedCheatPosition) @@ -141,7 +142,7 @@ class CheatsViewModel : ViewModel() { fun deleteSelectedCheat() { val position = selectedCheatPosition setSelectedCheat(null, -1) - cheatEngine!!.removeCheat(position) + CheatEngine.removeCheat(position) cheatsNeedSaving = true load() notifyCheatDeleted(position) diff --git a/src/android/app/src/main/jni/cheats/cheat_engine.cpp b/src/android/app/src/main/jni/cheats/cheat_engine.cpp index 5010bd14f1..9a6a6f37f0 100644 --- a/src/android/app/src/main/jni/cheats/cheat_engine.cpp +++ b/src/android/app/src/main/jni/cheats/cheat_engine.cpp @@ -15,24 +15,24 @@ extern "C" { -static Cheats::CheatEngine* GetPointer(JNIEnv* env, jobject obj) { - return reinterpret_cast( - env->GetLongField(obj, IDCache::GetCheatEnginePointer())); +static Cheats::CheatEngine& GetEngine() { + Core::System& system{Core::System::GetInstance()}; + return system.CheatEngine(); } -JNIEXPORT jlong JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_initialize( +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_loadCheatFile( JNIEnv* env, jclass, jlong title_id) { - return reinterpret_cast(new Cheats::CheatEngine(title_id, Core::System::GetInstance())); + GetEngine().LoadCheatFile(title_id); } -JNIEXPORT void JNICALL -Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_finalize(JNIEnv* env, jobject obj) { - delete GetPointer(env, obj); +JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_saveCheatFile( + JNIEnv* env, jclass, jlong title_id) { + GetEngine().SaveCheatFile(title_id); } JNIEXPORT jobjectArray JNICALL -Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_getCheats(JNIEnv* env, jobject obj) { - auto cheats = GetPointer(env, obj)->GetCheats(); +Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_getCheats(JNIEnv* env, jclass) { + auto cheats = GetEngine().GetCheats(); const jobjectArray array = env->NewObjectArray(static_cast(cheats.size()), IDCache::GetCheatClass(), nullptr); @@ -45,22 +45,19 @@ Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_getCheats(JNIEnv* en } JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_addCheat( - JNIEnv* env, jobject obj, jobject j_cheat) { - GetPointer(env, obj)->AddCheat(*CheatFromJava(env, j_cheat)); + JNIEnv* env, jclass, jobject j_cheat) { + auto cheat = *CheatFromJava(env, j_cheat); + GetEngine().AddCheat(std::move(cheat)); } JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_removeCheat( - JNIEnv* env, jobject obj, jint index) { - GetPointer(env, obj)->RemoveCheat(index); + JNIEnv* env, jclass, jint index) { + GetEngine().RemoveCheat(index); } JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_updateCheat( - JNIEnv* env, jobject obj, jint index, jobject j_new_cheat) { - GetPointer(env, obj)->UpdateCheat(index, *CheatFromJava(env, j_new_cheat)); -} - -JNIEXPORT void JNICALL Java_org_citra_citra_1emu_features_cheats_model_CheatEngine_saveCheatFile( - JNIEnv* env, jobject obj) { - GetPointer(env, obj)->SaveCheatFile(); + JNIEnv* env, jclass, jint index, jobject j_new_cheat) { + auto cheat = *CheatFromJava(env, j_new_cheat); + GetEngine().UpdateCheat(index, std::move(cheat)); } } diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp index e7be212796..f1c16fc9f3 100644 --- a/src/android/app/src/main/jni/id_cache.cpp +++ b/src/android/app/src/main/jni/id_cache.cpp @@ -35,8 +35,6 @@ static jclass s_cheat_class; static jfieldID s_cheat_pointer; static jmethodID s_cheat_constructor; -static jfieldID s_cheat_engine_pointer; - static jfieldID s_game_info_pointer; static jclass s_disk_cache_progress_class; @@ -116,10 +114,6 @@ jmethodID GetCheatConstructor() { return s_cheat_constructor; } -jfieldID GetCheatEnginePointer() { - return s_cheat_engine_pointer; -} - jfieldID GetGameInfoPointer() { return s_game_info_pointer; } @@ -195,12 +189,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { s_cheat_constructor = env->GetMethodID(cheat_class, "", "(J)V"); env->DeleteLocalRef(cheat_class); - // Initialize CheatEngine - const jclass cheat_engine_class = - env->FindClass("org/citra/citra_emu/features/cheats/model/CheatEngine"); - s_cheat_engine_pointer = env->GetFieldID(cheat_engine_class, "mPointer", "J"); - env->DeleteLocalRef(cheat_engine_class); - // Initialize GameInfo const jclass game_info_class = env->FindClass("org/citra/citra_emu/model/GameInfo"); s_game_info_pointer = env->GetFieldID(game_info_class, "pointer", "J"); diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h index 3e6d3eb930..7c08a1c0bf 100644 --- a/src/android/app/src/main/jni/id_cache.h +++ b/src/android/app/src/main/jni/id_cache.h @@ -35,8 +35,6 @@ jclass GetCheatClass(); jfieldID GetCheatPointer(); jmethodID GetCheatConstructor(); -jfieldID GetCheatEnginePointer(); - jfieldID GetGameInfoPointer(); jclass GetDiskCacheProgressClass(); diff --git a/src/citra_qt/configuration/configure_cheats.cpp b/src/citra_qt/configuration/configure_cheats.cpp index c589a62e60..aa67f74400 100644 --- a/src/citra_qt/configuration/configure_cheats.cpp +++ b/src/citra_qt/configuration/configure_cheats.cpp @@ -11,8 +11,10 @@ #include "core/cheats/gateway_cheat.h" #include "ui_configure_cheats.h" -ConfigureCheats::ConfigureCheats(Core::System& system, u64 title_id_, QWidget* parent) - : QWidget(parent), ui(std::make_unique()), title_id{title_id_} { +ConfigureCheats::ConfigureCheats(Cheats::CheatEngine& cheat_engine_, u64 title_id_, QWidget* parent) + : QWidget(parent), + ui(std::make_unique()), cheat_engine{cheat_engine_}, title_id{ + title_id_} { // Setup gui control settings ui->setupUi(this); ui->tableCheats->setColumnWidth(0, 30); @@ -34,15 +36,14 @@ ConfigureCheats::ConfigureCheats(Core::System& system, u64 title_id_, QWidget* p [this] { SaveCheat(ui->tableCheats->currentRow()); }); connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureCheats::OnDeleteCheat); - cheat_engine = std::make_unique(title_id, system); - + cheat_engine.LoadCheatFile(title_id); LoadCheats(); } ConfigureCheats::~ConfigureCheats() = default; void ConfigureCheats::LoadCheats() { - cheats = cheat_engine->GetCheats(); + cheats = cheat_engine.GetCheats(); const int cheats_count = static_cast(cheats.size()); ui->tableCheats->setRowCount(cheats_count); @@ -106,12 +107,12 @@ bool ConfigureCheats::SaveCheat(int row) { ui->textNotes->toPlainText().toStdString()); if (newly_created) { - cheat_engine->AddCheat(cheat); + cheat_engine.AddCheat(std::move(cheat)); newly_created = false; } else { - cheat_engine->UpdateCheat(row, cheat); + cheat_engine.UpdateCheat(row, std::move(cheat)); } - cheat_engine->SaveCheatFile(); + cheat_engine.SaveCheatFile(title_id); int previous_row = ui->tableCheats->currentRow(); int previous_col = ui->tableCheats->currentColumn(); @@ -161,7 +162,7 @@ void ConfigureCheats::OnCheckChanged(int state) { const QCheckBox* checkbox = qobject_cast(sender()); int row = static_cast(checkbox->property("row").toInt()); cheats[row]->SetEnabled(state); - cheat_engine->SaveCheatFile(); + cheat_engine.SaveCheatFile(title_id); } void ConfigureCheats::OnTextEdited() { @@ -173,8 +174,8 @@ void ConfigureCheats::OnDeleteCheat() { if (newly_created) { newly_created = false; } else { - cheat_engine->RemoveCheat(ui->tableCheats->currentRow()); - cheat_engine->SaveCheatFile(); + cheat_engine.RemoveCheat(ui->tableCheats->currentRow()); + cheat_engine.SaveCheatFile(title_id); } LoadCheats(); diff --git a/src/citra_qt/configuration/configure_cheats.h b/src/citra_qt/configuration/configure_cheats.h index 28dcb72e58..0c9f0323c2 100644 --- a/src/citra_qt/configuration/configure_cheats.h +++ b/src/citra_qt/configuration/configure_cheats.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include "common/common_types.h" @@ -25,7 +26,8 @@ class ConfigureCheats : public QWidget { Q_OBJECT public: - explicit ConfigureCheats(Core::System& system, u64 title_id, QWidget* parent = nullptr); + explicit ConfigureCheats(Cheats::CheatEngine& cheat_engine, u64 title_id_, + QWidget* parent = nullptr); ~ConfigureCheats(); bool ApplyConfiguration(); @@ -58,9 +60,9 @@ private slots: private: std::unique_ptr ui; - std::vector> cheats; + Cheats::CheatEngine& cheat_engine; + std::span> cheats; bool edited = false, newly_created = false; int last_row = -1, last_col = -1; u64 title_id; - std::unique_ptr cheat_engine; }; diff --git a/src/citra_qt/configuration/configure_per_game.cpp b/src/citra_qt/configuration/configure_per_game.cpp index c5aa3f5ca6..5b4d400440 100644 --- a/src/citra_qt/configuration/configure_per_game.cpp +++ b/src/citra_qt/configuration/configure_per_game.cpp @@ -38,7 +38,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString graphics_tab = std::make_unique(physical_devices, is_powered_on, this); system_tab = std::make_unique(system, this); debug_tab = std::make_unique(is_powered_on, this); - cheat_tab = std::make_unique(system, title_id, this); + cheat_tab = std::make_unique(system.CheatEngine(), title_id, this); ui->setupUi(this); diff --git a/src/core/cheats/cheats.cpp b/src/core/cheats/cheats.cpp index aff31f1309..30b8e56cc7 100644 --- a/src/core/cheats/cheats.cpp +++ b/src/core/cheats/cheats.cpp @@ -10,7 +10,6 @@ #include "core/cheats/gateway_cheat.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/hle/kernel/process.h" namespace Cheats { @@ -18,11 +17,11 @@ namespace Cheats { // we use the same value constexpr u64 run_interval_ticks = 50'000'000; -CheatEngine::CheatEngine(u64 title_id_, Core::System& system_) - : system(system_), title_id{title_id_} { - LoadCheatFile(); +CheatEngine::CheatEngine(Core::System& system_) : system{system_} {} + +CheatEngine::~CheatEngine() { if (system.IsPoweredOn()) { - Connect(); + system.CoreTiming().UnscheduleEvent(event, 0); } } @@ -33,24 +32,18 @@ void CheatEngine::Connect() { system.CoreTiming().ScheduleEvent(run_interval_ticks, event); } -CheatEngine::~CheatEngine() { - if (system.IsPoweredOn()) { - system.CoreTiming().UnscheduleEvent(event, 0); - } -} - -std::vector> CheatEngine::GetCheats() const { - std::shared_lock lock(cheats_list_mutex); +std::span> CheatEngine::GetCheats() const { + std::shared_lock lock{cheats_list_mutex}; return cheats_list; } -void CheatEngine::AddCheat(const std::shared_ptr& cheat) { - std::unique_lock lock(cheats_list_mutex); - cheats_list.push_back(cheat); +void CheatEngine::AddCheat(std::shared_ptr&& cheat) { + std::unique_lock lock{cheats_list_mutex}; + cheats_list.push_back(std::move(cheat)); } void CheatEngine::RemoveCheat(std::size_t index) { - std::unique_lock lock(cheats_list_mutex); + std::unique_lock lock{cheats_list_mutex}; if (index < 0 || index >= cheats_list.size()) { LOG_ERROR(Core_Cheats, "Invalid index {}", index); return; @@ -58,16 +51,16 @@ void CheatEngine::RemoveCheat(std::size_t index) { cheats_list.erase(cheats_list.begin() + index); } -void CheatEngine::UpdateCheat(std::size_t index, const std::shared_ptr& new_cheat) { - std::unique_lock lock(cheats_list_mutex); +void CheatEngine::UpdateCheat(std::size_t index, std::shared_ptr&& new_cheat) { + std::unique_lock lock{cheats_list_mutex}; if (index < 0 || index >= cheats_list.size()) { LOG_ERROR(Core_Cheats, "Invalid index {}", index); return; } - cheats_list[index] = new_cheat; + cheats_list[index] = std::move(new_cheat); } -void CheatEngine::SaveCheatFile() const { +void CheatEngine::SaveCheatFile(u64 title_id) const { const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir); const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id); @@ -82,7 +75,14 @@ void CheatEngine::SaveCheatFile() const { } } -void CheatEngine::LoadCheatFile() { +void CheatEngine::LoadCheatFile(u64 title_id) { + { + std::unique_lock lock{cheats_list_mutex}; + if (loaded_title_id.has_value() && loaded_title_id == title_id) { + return; + } + } + const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir); const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id); @@ -90,20 +90,22 @@ void CheatEngine::LoadCheatFile() { FileUtil::CreateDir(cheat_dir); } - if (!FileUtil::Exists(filepath)) + if (!FileUtil::Exists(filepath)) { return; + } auto gateway_cheats = GatewayCheat::LoadFile(filepath); { - std::unique_lock lock(cheats_list_mutex); - std::move(gateway_cheats.begin(), gateway_cheats.end(), std::back_inserter(cheats_list)); + std::unique_lock lock{cheats_list_mutex}; + loaded_title_id = title_id; + cheats_list = std::move(gateway_cheats); } } void CheatEngine::RunCallback([[maybe_unused]] std::uintptr_t user_data, s64 cycles_late) { { - std::shared_lock lock(cheats_list_mutex); - for (auto& cheat : cheats_list) { + std::shared_lock lock{cheats_list_mutex}; + for (const auto& cheat : cheats_list) { if (cheat->IsEnabled()) { cheat->Execute(system); } diff --git a/src/core/cheats/cheats.h b/src/core/cheats/cheats.h index f19212e601..8f8127d743 100644 --- a/src/core/cheats/cheats.h +++ b/src/core/cheats/cheats.h @@ -5,7 +5,9 @@ #pragma once #include +#include #include +#include #include #include "common/common_types.h" @@ -24,22 +26,39 @@ class CheatBase; class CheatEngine { public: - explicit CheatEngine(u64 title_id_, Core::System& system); + explicit CheatEngine(Core::System& system); ~CheatEngine(); + + /// Registers the cheat execution callback. void Connect(); - std::vector> GetCheats() const; - void AddCheat(const std::shared_ptr& cheat); + + /// Returns a span of the currently active cheats. + std::span> GetCheats() const; + + /// Adds a cheat to the cheat engine. + void AddCheat(std::shared_ptr&& cheat); + + /// Removes a cheat at the specified index in the cheats list. void RemoveCheat(std::size_t index); - void UpdateCheat(std::size_t index, const std::shared_ptr& new_cheat); - void SaveCheatFile() const; + + /// Updates a cheat at the specified index in the cheats list. + void UpdateCheat(std::size_t index, std::shared_ptr&& new_cheat); + + /// Loads the cheat file from disk for the specified title id. + void LoadCheatFile(u64 title_id); + + /// Saves currently active cheats to file for the specified title id. + void SaveCheatFile(u64 title_id) const; private: - void LoadCheatFile(); + /// The cheat execution callback. void RunCallback(std::uintptr_t user_data, s64 cycles_late); + +private: + Core::System& system; + Core::TimingEventType* event; + std::optional loaded_title_id; std::vector> cheats_list; mutable std::shared_mutex cheats_list_mutex; - Core::TimingEventType* event; - Core::System& system; - u64 title_id; }; } // namespace Cheats diff --git a/src/core/cheats/gateway_cheat.cpp b/src/core/cheats/gateway_cheat.cpp index c7782127de..4f9456699e 100644 --- a/src/core/cheats/gateway_cheat.cpp +++ b/src/core/cheats/gateway_cheat.cpp @@ -472,8 +472,8 @@ std::string GatewayCheat::ToString() const { return result; } -std::vector> GatewayCheat::LoadFile(const std::string& filepath) { - std::vector> cheats; +std::vector> GatewayCheat::LoadFile(const std::string& filepath) { + std::vector> cheats; boost::iostreams::stream file; FileUtil::OpenFStream(file, filepath); @@ -493,7 +493,7 @@ std::vector> GatewayCheat::LoadFile(const std::string line = Common::StripSpaces(line); // remove spaces at front and end if (line.length() >= 2 && line.front() == '[') { if (!cheat_lines.empty()) { - cheats.push_back(std::make_unique(name, cheat_lines, comments)); + cheats.push_back(std::make_shared(name, cheat_lines, comments)); cheats.back()->SetEnabled(enabled); enabled = false; } @@ -511,7 +511,7 @@ std::vector> GatewayCheat::LoadFile(const std::string } } if (!cheat_lines.empty()) { - cheats.push_back(std::make_unique(name, cheat_lines, comments)); + cheats.push_back(std::make_shared(name, cheat_lines, comments)); cheats.back()->SetEnabled(enabled); } return cheats; diff --git a/src/core/cheats/gateway_cheat.h b/src/core/cheats/gateway_cheat.h index 14c81786be..ff200af59d 100644 --- a/src/core/cheats/gateway_cheat.h +++ b/src/core/cheats/gateway_cheat.h @@ -77,7 +77,7 @@ public: /// (there might be multiple lines of those hex numbers) /// Comment lines start with a '*' /// This function will pares the file for such structures - static std::vector> LoadFile(const std::string& filepath); + static std::vector> LoadFile(const std::string& filepath); private: std::atomic enabled = false; diff --git a/src/core/core.cpp b/src/core/core.cpp index b0faf08c9b..56211d9795 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -72,7 +72,7 @@ Core::Timing& Global() { return System::GetInstance().CoreTiming(); } -System::System() : movie{*this} {} +System::System() : movie{*this}, cheat_engine{*this} {} System::~System() = default; @@ -320,7 +320,10 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", static_cast(load_result)); } - cheat_engine = std::make_unique(title_id, *this); + + cheat_engine.LoadCheatFile(title_id); + cheat_engine.Connect(); + perf_stats = std::make_unique(title_id); if (Settings::values.dump_textures) { @@ -502,11 +505,11 @@ const Memory::MemorySystem& System::Memory() const { } Cheats::CheatEngine& System::CheatEngine() { - return *cheat_engine; + return cheat_engine; } const Cheats::CheatEngine& System::CheatEngine() const { - return *cheat_engine; + return cheat_engine; } void System::RegisterVideoDumper(std::shared_ptr dumper) { @@ -560,7 +563,6 @@ void System::Shutdown(bool is_deserializing) { if (!is_deserializing) { GDBStub::Shutdown(); perf_stats.reset(); - cheat_engine.reset(); app_loader.reset(); } custom_tex_manager.reset(); @@ -718,7 +720,7 @@ void System::serialize(Archive& ar, const unsigned int file_version) { if (Archive::is_loading::value) { timing->UnlockEventQueue(); memory->SetDSP(*dsp_core); - cheat_engine->Connect(); + cheat_engine.Connect(); gpu->Sync(); // Re-register gpu callback, because gsp service changed after service_manager got diff --git a/src/core/core.h b/src/core/core.h index 87db181795..66914f7dff 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -11,6 +11,7 @@ #include #include "common/common_types.h" #include "core/arm/arm_interface.h" +#include "core/cheats/cheats.h" #include "core/movie.h" #include "core/perf_stats.h" @@ -48,10 +49,6 @@ struct New3dsHwCapabilities; enum class MemoryMode : u8; } // namespace Kernel -namespace Cheats { -class CheatEngine; -} - namespace VideoDumper { class Backend; } @@ -401,7 +398,7 @@ private: Core::Movie movie; /// Cheats manager - std::unique_ptr cheat_engine; + Cheats::CheatEngine cheat_engine; /// Video dumper backend std::shared_ptr video_dumper;