mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	cheats: Use global cheat engine (#7291)
* cheats: Use global cheat engine * cheats: Prevent wasted double-load of cheat file. * android: Fix for cheat engine updates. --------- Co-authored-by: GPUCode <geoster3d@gmail.com>
This commit is contained in:
		
							parent
							
								
									5a7f615da1
								
							
						
					
					
						commit
						7dd9174d31
					
				
					 14 changed files with 120 additions and 125 deletions
				
			
		|  | @ -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<Cheat> | ||||
| 
 | ||||
|     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 | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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<Cheat> | ||||
|     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) | ||||
|  |  | |||
|  | @ -15,24 +15,24 @@ | |||
| 
 | ||||
| extern "C" { | ||||
| 
 | ||||
| static Cheats::CheatEngine* GetPointer(JNIEnv* env, jobject obj) { | ||||
|     return reinterpret_cast<Cheats::CheatEngine*>( | ||||
|         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<jlong>(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<jsize>(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)); | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -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, "<init>", "(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"); | ||||
|  |  | |||
|  | @ -35,8 +35,6 @@ jclass GetCheatClass(); | |||
| jfieldID GetCheatPointer(); | ||||
| jmethodID GetCheatConstructor(); | ||||
| 
 | ||||
| jfieldID GetCheatEnginePointer(); | ||||
| 
 | ||||
| jfieldID GetGameInfoPointer(); | ||||
| 
 | ||||
| jclass GetDiskCacheProgressClass(); | ||||
|  |  | |||
|  | @ -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<Ui::ConfigureCheats>()), title_id{title_id_} { | ||||
| ConfigureCheats::ConfigureCheats(Cheats::CheatEngine& cheat_engine_, u64 title_id_, QWidget* parent) | ||||
|     : QWidget(parent), | ||||
|       ui(std::make_unique<Ui::ConfigureCheats>()), 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<Cheats::CheatEngine>(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<int>(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<QCheckBox*>(sender()); | ||||
|     int row = static_cast<int>(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(); | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <span> | ||||
| #include <QWidget> | ||||
| #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::ConfigureCheats> ui; | ||||
|     std::vector<std::shared_ptr<Cheats::CheatBase>> cheats; | ||||
|     Cheats::CheatEngine& cheat_engine; | ||||
|     std::span<const std::shared_ptr<Cheats::CheatBase>> cheats; | ||||
|     bool edited = false, newly_created = false; | ||||
|     int last_row = -1, last_col = -1; | ||||
|     u64 title_id; | ||||
|     std::unique_ptr<Cheats::CheatEngine> cheat_engine; | ||||
| }; | ||||
|  |  | |||
|  | @ -38,7 +38,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString | |||
|     graphics_tab = std::make_unique<ConfigureGraphics>(physical_devices, is_powered_on, this); | ||||
|     system_tab = std::make_unique<ConfigureSystem>(system, this); | ||||
|     debug_tab = std::make_unique<ConfigureDebug>(is_powered_on, this); | ||||
|     cheat_tab = std::make_unique<ConfigureCheats>(system, title_id, this); | ||||
|     cheat_tab = std::make_unique<ConfigureCheats>(system.CheatEngine(), title_id, this); | ||||
| 
 | ||||
|     ui->setupUi(this); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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<std::shared_ptr<CheatBase>> CheatEngine::GetCheats() const { | ||||
|     std::shared_lock<std::shared_mutex> lock(cheats_list_mutex); | ||||
| std::span<const std::shared_ptr<CheatBase>> CheatEngine::GetCheats() const { | ||||
|     std::shared_lock lock{cheats_list_mutex}; | ||||
|     return cheats_list; | ||||
| } | ||||
| 
 | ||||
| void CheatEngine::AddCheat(const std::shared_ptr<CheatBase>& cheat) { | ||||
|     std::unique_lock<std::shared_mutex> lock(cheats_list_mutex); | ||||
|     cheats_list.push_back(cheat); | ||||
| void CheatEngine::AddCheat(std::shared_ptr<CheatBase>&& 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<std::shared_mutex> 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<CheatBase>& new_cheat) { | ||||
|     std::unique_lock<std::shared_mutex> lock(cheats_list_mutex); | ||||
| void CheatEngine::UpdateCheat(std::size_t index, std::shared_ptr<CheatBase>&& 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<std::shared_mutex> 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<std::shared_mutex> 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); | ||||
|             } | ||||
|  |  | |||
|  | @ -5,7 +5,9 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <optional> | ||||
| #include <shared_mutex> | ||||
| #include <span> | ||||
| #include <vector> | ||||
| #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<std::shared_ptr<CheatBase>> GetCheats() const; | ||||
|     void AddCheat(const std::shared_ptr<CheatBase>& cheat); | ||||
| 
 | ||||
|     /// Returns a span of the currently active cheats.
 | ||||
|     std::span<const std::shared_ptr<CheatBase>> GetCheats() const; | ||||
| 
 | ||||
|     /// Adds a cheat to the cheat engine.
 | ||||
|     void AddCheat(std::shared_ptr<CheatBase>&& 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<CheatBase>& 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<CheatBase>&& 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<u64> loaded_title_id; | ||||
|     std::vector<std::shared_ptr<CheatBase>> cheats_list; | ||||
|     mutable std::shared_mutex cheats_list_mutex; | ||||
|     Core::TimingEventType* event; | ||||
|     Core::System& system; | ||||
|     u64 title_id; | ||||
| }; | ||||
| } // namespace Cheats
 | ||||
|  |  | |||
|  | @ -472,8 +472,8 @@ std::string GatewayCheat::ToString() const { | |||
|     return result; | ||||
| } | ||||
| 
 | ||||
| std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string& filepath) { | ||||
|     std::vector<std::unique_ptr<CheatBase>> cheats; | ||||
| std::vector<std::shared_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string& filepath) { | ||||
|     std::vector<std::shared_ptr<CheatBase>> cheats; | ||||
| 
 | ||||
|     boost::iostreams::stream<boost::iostreams::file_descriptor_source> file; | ||||
|     FileUtil::OpenFStream<std::ios_base::in>(file, filepath); | ||||
|  | @ -493,7 +493,7 @@ std::vector<std::unique_ptr<CheatBase>> 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<GatewayCheat>(name, cheat_lines, comments)); | ||||
|                 cheats.push_back(std::make_shared<GatewayCheat>(name, cheat_lines, comments)); | ||||
|                 cheats.back()->SetEnabled(enabled); | ||||
|                 enabled = false; | ||||
|             } | ||||
|  | @ -511,7 +511,7 @@ std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string | |||
|         } | ||||
|     } | ||||
|     if (!cheat_lines.empty()) { | ||||
|         cheats.push_back(std::make_unique<GatewayCheat>(name, cheat_lines, comments)); | ||||
|         cheats.push_back(std::make_shared<GatewayCheat>(name, cheat_lines, comments)); | ||||
|         cheats.back()->SetEnabled(enabled); | ||||
|     } | ||||
|     return cheats; | ||||
|  |  | |||
|  | @ -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<std::unique_ptr<CheatBase>> LoadFile(const std::string& filepath); | ||||
|     static std::vector<std::shared_ptr<CheatBase>> LoadFile(const std::string& filepath); | ||||
| 
 | ||||
| private: | ||||
|     std::atomic<bool> enabled = false; | ||||
|  |  | |||
|  | @ -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<u32>(load_result)); | ||||
|     } | ||||
|     cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, *this); | ||||
| 
 | ||||
|     cheat_engine.LoadCheatFile(title_id); | ||||
|     cheat_engine.Connect(); | ||||
| 
 | ||||
|     perf_stats = std::make_unique<PerfStats>(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<VideoDumper::Backend> 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
 | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
| #include <boost/serialization/version.hpp> | ||||
| #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<Cheats::CheatEngine> cheat_engine; | ||||
|     Cheats::CheatEngine cheat_engine; | ||||
| 
 | ||||
|     /// Video dumper backend
 | ||||
|     std::shared_ptr<VideoDumper::Backend> video_dumper; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue