From 16272f49750699a06937defea5d7ee140eed1ac1 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sun, 12 Jul 2015 01:49:12 +0200 Subject: [PATCH 1/3] SaveState/DolphinWX: Display time and date of savestate when a slot is selected, or Empty if no savestate exists in the slot. --- Source/Core/Common/Timer.cpp | 15 +++++++++++++-- Source/Core/Common/Timer.h | 7 +++++++ Source/Core/Core/State.cpp | 13 +++++++++++++ Source/Core/Core/State.h | 4 ++++ Source/Core/DolphinWX/FrameTools.cpp | 2 +- 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Source/Core/Common/Timer.cpp b/Source/Core/Common/Timer.cpp index 451e6a0725..4ad69fdc23 100644 --- a/Source/Core/Common/Timer.cpp +++ b/Source/Core/Common/Timer.cpp @@ -225,7 +225,6 @@ std::string Timer::GetTimeFormatted() } // Returns a timestamp with decimals for precise time comparisons -// ---------------- double Timer::GetDoubleTime() { #ifdef _WIN32 @@ -245,7 +244,7 @@ double Timer::GetDoubleTime() // sure that we are detecting actual actions, perhaps 60 seconds is // enough really, but I leave a year of seconds anyway, in case the // user's clock is incorrect or something like that. - TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); + TmpSeconds = TmpSeconds - DOUBLE_TIME_OFFSET; // Make a smaller integer that fits in the double u32 Seconds = (u32)TmpSeconds; @@ -261,4 +260,16 @@ double Timer::GetDoubleTime() return TmpTime; } +// Formats a timestamp from GetDoubleTime() into a date and time string +std::string Timer::GetDateTimeFormatted(double time) +{ + // revert adjustments from GetDoubleTime() to get a normal Unix timestamp again + time_t seconds = (time_t)time + DOUBLE_TIME_OFFSET; + tm* localTime = localtime(&seconds); + + char tmp[32] = {}; + strftime(tmp, sizeof(tmp), "%x %X", localTime); + return tmp; +} + } // Namespace Common diff --git a/Source/Core/Common/Timer.h b/Source/Core/Common/Timer.h index e5b828af25..cc6d6549c4 100644 --- a/Source/Core/Common/Timer.h +++ b/Source/Core/Common/Timer.h @@ -26,15 +26,22 @@ public: static void RestoreResolution(); static u64 GetTimeSinceJan1970(); static u64 GetLocalTimeSinceJan1970(); + // Returns a timestamp with decimals for precise time comparisons static double GetDoubleTime(); static std::string GetTimeFormatted(); + // Formats a timestamp from GetDoubleTime() into a date and time string + static std::string GetDateTimeFormatted(double time); std::string GetTimeElapsedFormatted() const; u64 GetTimeElapsed(); static u32 GetTimeMs(); static u64 GetTimeUs(); + // Arbitrarily chosen value (38 years) that is subtracted in GetDoubleTime() + // to increase sub-second precision of the resulting double timestamp + static const int DOUBLE_TIME_OFFSET = (38 * 365 * 24 * 60 * 60); + private: u64 m_LastTime; u64 m_StartTime; diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 129aaa15ea..4aaa63dff9 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -435,6 +435,19 @@ bool ReadHeader(const std::string& filename, StateHeader& header) return true; } +std::string GetInfoStringOfSlot(int slot) +{ + std::string filename = MakeStateFilename(slot); + if (!File::Exists(filename)) + return "Empty"; + + State::StateHeader header; + if (!ReadHeader(filename, header)) + return "Unknown"; + + return Common::Timer::GetDateTimeFormatted(header.time); +} + static void LoadFileStateData(const std::string& filename, std::vector& ret_data) { Flush(); diff --git a/Source/Core/Core/State.h b/Source/Core/Core/State.h index 342f761697..c16a22a299 100644 --- a/Source/Core/Core/State.h +++ b/Source/Core/Core/State.h @@ -33,6 +33,10 @@ void EnableCompression(bool compression); bool ReadHeader(const std::string& filename, StateHeader& header); +// Returns a string containing information of the savestate in the given slot +// which can be presented to the user for identification purposes +std::string GetInfoStringOfSlot(int slot); + // These don't happen instantly - they get scheduled as events. // ...But only if we're not in the main CPU thread. // If we're in the main CPU thread then they run immediately instead diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index d79981b56a..a74ce4645f 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -1680,7 +1680,7 @@ void CFrame::OnFrameSkip(wxCommandEvent& event) void CFrame::OnSelectSlot(wxCommandEvent& event) { g_saveSlot = event.GetId() - IDM_SELECT_SLOT_1 + 1; - Core::DisplayMessage(StringFromFormat("Selected slot %d", g_saveSlot), 1000); + Core::DisplayMessage(StringFromFormat("Selected slot %d - %s", g_saveSlot, State::GetInfoStringOfSlot(g_saveSlot).c_str()), 2500); } void CFrame::OnLoadCurrentSlot(wxCommandEvent& event) From 429f4ea158236174a4c0892b034c2b336ff8c0ee Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sun, 12 Jul 2015 04:04:35 +0200 Subject: [PATCH 2/3] SaveState/DolphinWX: Display time and date of savestate next to the load/save/select slot menu options. --- Source/Core/Core/State.cpp | 2 ++ Source/Core/DolphinWX/FrameTools.cpp | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 4aaa63dff9..f239521882 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -17,6 +17,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" +#include "Core/Host.h" #include "Core/Movie.h" #include "Core/State.h" #include "Core/HW/CPU.h" @@ -373,6 +374,7 @@ static void CompressAndDumpState(CompressAndDumpState_args save_args) } Core::DisplayMessage(StringFromFormat("Saved State to %s", filename.c_str()), 2000); + Host_UpdateMainFrame(); } void SaveAs(const std::string& filename, bool wait) diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index a74ce4645f..d5e80860c5 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -462,8 +462,8 @@ wxString CFrame::GetMenuLabel(int Id) case HK_LOAD_STATE_SLOT_8: case HK_LOAD_STATE_SLOT_9: case HK_LOAD_STATE_SLOT_10: - Label = wxString::Format(_("Slot %i"), - Id - HK_LOAD_STATE_SLOT_1 + 1); + Label = wxString::Format(_("Slot %i - %s"), + Id - HK_LOAD_STATE_SLOT_1 + 1, State::GetInfoStringOfSlot(Id - HK_LOAD_STATE_SLOT_1 + 1).c_str()); break; case HK_SAVE_STATE_SLOT_1: @@ -476,8 +476,8 @@ wxString CFrame::GetMenuLabel(int Id) case HK_SAVE_STATE_SLOT_8: case HK_SAVE_STATE_SLOT_9: case HK_SAVE_STATE_SLOT_10: - Label = wxString::Format(_("Slot %i"), - Id - HK_SAVE_STATE_SLOT_1 + 1); + Label = wxString::Format(_("Slot %i - %s"), + Id - HK_SAVE_STATE_SLOT_1 + 1, State::GetInfoStringOfSlot(Id - HK_SAVE_STATE_SLOT_1 + 1).c_str()); break; case HK_SAVE_STATE_FILE: Label = _("Save State..."); @@ -522,7 +522,8 @@ wxString CFrame::GetMenuLabel(int Id) case HK_SELECT_STATE_SLOT_8: case HK_SELECT_STATE_SLOT_9: case HK_SELECT_STATE_SLOT_10: - Label = wxString::Format(_("Select Slot %i"), Id - HK_SELECT_STATE_SLOT_1 + 1); + Label = wxString::Format(_("Select Slot %i - %s"), + Id - HK_SELECT_STATE_SLOT_1 + 1, State::GetInfoStringOfSlot(Id - HK_SELECT_STATE_SLOT_1 + 1).c_str()); break; From 1772eeb32f2594e57895c4655638638c4e6ab11f Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Fri, 24 Jul 2015 17:13:40 +0200 Subject: [PATCH 3/3] State.cpp: Extract the savestate version logic into its own function for clarity. --- Source/Core/Core/State.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index f239521882..5678e58244 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -119,7 +119,8 @@ void EnableCompression(bool compression) g_use_compression = compression; } -static std::string DoState(PointerWrap& p) +// Returns true if state version matches current Dolphin state version, false otherwise. +static bool DoStateVersion(PointerWrap& p, std::string* version_created_by) { u32 version = STATE_VERSION; { @@ -129,15 +130,15 @@ static std::string DoState(PointerWrap& p) version = cookie - COOKIE_BASE; } - std::string version_created_by = scm_rev_str; + *version_created_by = scm_rev_str; if (version > 42) - p.Do(version_created_by); + p.Do(*version_created_by); else - version_created_by.clear(); + version_created_by->clear(); if (version != STATE_VERSION) { - if (version_created_by.empty() && s_old_versions.count(version)) + if (version_created_by->empty() && s_old_versions.count(version)) { // The savestate is from an old version that doesn't // save the Dolphin version number to savestates, but @@ -148,9 +149,21 @@ static std::string DoState(PointerWrap& p) std::string oldest_version = version_range.first; std::string newest_version = version_range.second; - version_created_by = "Dolphin " + oldest_version + " - " + newest_version; + *version_created_by = "Dolphin " + oldest_version + " - " + newest_version; } + return false; + } + + p.DoMarker("Version"); + return true; +} + +static std::string DoState(PointerWrap& p) +{ + std::string version_created_by; + if (!DoStateVersion(p, &version_created_by)) + { // because the version doesn't match, fail. // this will trigger an OSD message like "Can't load state from other revisions" // we could use the version numbers to maintain some level of backward compatibility, but currently don't. @@ -158,8 +171,6 @@ static std::string DoState(PointerWrap& p) return version_created_by; } - p.DoMarker("Version"); - // Begin with video backend, so that it gets a chance to clear its caches and writeback modified things to RAM g_video_backend->DoState(p); p.DoMarker("video_backend");