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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue