mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #6419 from vitor-k/states
Update zstd and improve savestates logging
This commit is contained in:
		
						commit
						5f81940e63
					
				
					 4 changed files with 49 additions and 35 deletions
				
			
		|  | @ -113,9 +113,10 @@ System::ResultStatus System::RunLoop(bool tight_loop) { | |||
|     case Signal::Shutdown: | ||||
|         return ResultStatus::ShutdownRequested; | ||||
|     case Signal::Load: { | ||||
|         LOG_INFO(Core, "Begin load"); | ||||
|         const u32 slot = param; | ||||
|         LOG_INFO(Core, "Begin load of slot {}", slot); | ||||
|         try { | ||||
|             System::LoadState(param); | ||||
|             System::LoadState(slot); | ||||
|             LOG_INFO(Core, "Load completed"); | ||||
|         } catch (const std::exception& e) { | ||||
|             LOG_ERROR(Core, "Error loading: {}", e.what()); | ||||
|  | @ -126,9 +127,10 @@ System::ResultStatus System::RunLoop(bool tight_loop) { | |||
|         return ResultStatus::Success; | ||||
|     } | ||||
|     case Signal::Save: { | ||||
|         LOG_INFO(Core, "Begin save"); | ||||
|         const u32 slot = param; | ||||
|         LOG_INFO(Core, "Begin save to slot {}", slot); | ||||
|         try { | ||||
|             System::SaveState(param); | ||||
|             System::SaveState(slot); | ||||
|             LOG_INFO(Core, "Save completed"); | ||||
|         } catch (const std::exception& e) { | ||||
|             LOG_ERROR(Core, "Error saving: {}", e.what()); | ||||
|  |  | |||
|  | @ -3,18 +3,15 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <boost/serialization/binary_object.hpp> | ||||
| #include <cryptopp/hex.h> | ||||
| #include "common/archives.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/scm_rev.h" | ||||
| #include "common/zstd_compression.h" | ||||
| #include "core/cheats/cheats.h" | ||||
| #include "core/core.h" | ||||
| #include "core/movie.h" | ||||
| #include "core/savestate.h" | ||||
| #include "network/network.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| 
 | ||||
|  | @ -25,19 +22,14 @@ struct CSTHeader { | |||
|     std::array<u8, 20> revision; /// Git hash of the revision this savestate was created with
 | ||||
|     u64_le time;                 /// The time when this save state was created
 | ||||
| 
 | ||||
|     std::array<u8, 216> reserved; /// Make heading 256 bytes so it has consistent size
 | ||||
| 
 | ||||
|     template <class Archive> | ||||
|     void serialize(Archive& ar, const unsigned int) { | ||||
|         ar& boost::serialization::binary_object(this, sizeof(CSTHeader)); | ||||
|     } | ||||
|     std::array<u8, 216> reserved{}; /// Make heading 256 bytes so it has consistent size
 | ||||
| }; | ||||
| static_assert(sizeof(CSTHeader) == 256, "CSTHeader should be 256 bytes"); | ||||
| #pragma pack(pop) | ||||
| 
 | ||||
| constexpr std::array<u8, 4> header_magic_bytes{{'C', 'S', 'T', 0x1B}}; | ||||
| 
 | ||||
| std::string GetSaveStatePath(u64 program_id, u32 slot) { | ||||
| static std::string GetSaveStatePath(u64 program_id, u32 slot) { | ||||
|     const u64 movie_id = Movie::GetInstance().GetCurrentMovieID(); | ||||
|     if (movie_id) { | ||||
|         return fmt::format("{}{:016X}.movie{:016X}.{:02d}.cst", | ||||
|  | @ -49,6 +41,30 @@ std::string GetSaveStatePath(u64 program_id, u32 slot) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| static bool ValidateSaveState(const CSTHeader& header, SaveStateInfo& info, u64 program_id, | ||||
|                               u32 slot) { | ||||
|     const auto path = GetSaveStatePath(program_id, slot); | ||||
|     if (header.filetype != header_magic_bytes) { | ||||
|         LOG_WARNING(Core, "Invalid save state file {}", path); | ||||
|         return false; | ||||
|     } | ||||
|     info.time = header.time; | ||||
| 
 | ||||
|     if (header.program_id != program_id) { | ||||
|         LOG_WARNING(Core, "Save state file isn't for the current game {}", path); | ||||
|         return false; | ||||
|     } | ||||
|     const std::string revision = fmt::format("{:02x}", fmt::join(header.revision, "")); | ||||
|     if (revision == Common::g_scm_rev) { | ||||
|         info.status = SaveStateInfo::ValidationStatus::OK; | ||||
|     } else { | ||||
|         LOG_WARNING(Core, "Save state file {} created from a different revision {}", path, | ||||
|                     revision); | ||||
|         info.status = SaveStateInfo::ValidationStatus::RevisionDismatch; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| std::vector<SaveStateInfo> ListSaveStates(u64 program_id) { | ||||
|     std::vector<SaveStateInfo> result; | ||||
|     for (u32 slot = 1; slot <= SaveStateSlotCount; ++slot) { | ||||
|  | @ -74,24 +90,10 @@ std::vector<SaveStateInfo> ListSaveStates(u64 program_id) { | |||
|             LOG_ERROR(Core, "Could not read from file {}", path); | ||||
|             continue; | ||||
|         } | ||||
|         if (header.filetype != header_magic_bytes) { | ||||
|             LOG_WARNING(Core, "Invalid save state file {}", path); | ||||
|         if (!ValidateSaveState(header, info, program_id, slot)) { | ||||
|             continue; | ||||
|         } | ||||
|         info.time = header.time; | ||||
| 
 | ||||
|         if (header.program_id != program_id) { | ||||
|             LOG_WARNING(Core, "Save state file isn't for the current game {}", path); | ||||
|             continue; | ||||
|         } | ||||
|         const std::string revision = fmt::format("{:02x}", fmt::join(header.revision, "")); | ||||
|         if (revision == Common::g_scm_rev) { | ||||
|             info.status = SaveStateInfo::ValidationStatus::OK; | ||||
|         } else { | ||||
|             LOG_WARNING(Core, "Save state file {} created from a different revision {}", path, | ||||
|                         revision); | ||||
|             info.status = SaveStateInfo::ValidationStatus::RevisionDismatch; | ||||
|         } | ||||
|         result.emplace_back(std::move(info)); | ||||
|     } | ||||
|     return result; | ||||
|  | @ -121,8 +123,8 @@ void System::SaveState(u32 slot) const { | |||
|     header.filetype = header_magic_bytes; | ||||
|     header.program_id = title_id; | ||||
|     std::string rev_bytes; | ||||
|     CryptoPP::StringSource(Common::g_scm_rev, true, | ||||
|                            new CryptoPP::HexDecoder(new CryptoPP::StringSink(rev_bytes))); | ||||
|     CryptoPP::StringSource ss(Common::g_scm_rev, true, | ||||
|                               new CryptoPP::HexDecoder(new CryptoPP::StringSink(rev_bytes))); | ||||
|     std::memcpy(header.revision.data(), rev_bytes.data(), sizeof(header.revision)); | ||||
|     header.time = std::chrono::duration_cast<std::chrono::seconds>( | ||||
|                       std::chrono::system_clock::now().time_since_epoch()) | ||||
|  | @ -146,7 +148,19 @@ void System::LoadState(u32 slot) { | |||
|         std::vector<u8> buffer(FileUtil::GetSize(path) - sizeof(CSTHeader)); | ||||
| 
 | ||||
|         FileUtil::IOFile file(path, "rb"); | ||||
|         file.Seek(sizeof(CSTHeader), SEEK_SET); // Skip header
 | ||||
| 
 | ||||
|         // load header
 | ||||
|         CSTHeader header; | ||||
|         if (file.ReadBytes(&header, sizeof(header)) != sizeof(header)) { | ||||
|             throw std::runtime_error("Could not read from file at " + path); | ||||
|         } | ||||
| 
 | ||||
|         // validate header
 | ||||
|         SaveStateInfo info; | ||||
|         if (!ValidateSaveState(header, info, title_id, slot)) { | ||||
|             throw std::runtime_error("Invalid savestate"); | ||||
|         } | ||||
| 
 | ||||
|         if (file.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) { | ||||
|             throw std::runtime_error("Could not read from file at " + path); | ||||
|         } | ||||
|  |  | |||
|  | @ -9,8 +9,6 @@ | |||
| 
 | ||||
| namespace Core { | ||||
| 
 | ||||
| struct CSTHeader; | ||||
| 
 | ||||
| struct SaveStateInfo { | ||||
|     u32 slot; | ||||
|     u64 time; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue