mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +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
				
			
		|  | @ -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