mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 16:19:28 +01:00
Merge pull request #12262 from AdmiralCurtiss/last-state-order-refactor
Core/State: Refactor logic for determining the relative age of existing savestates.
This commit is contained in:
commit
b32ac9353e
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "Core/State.h"
|
#include "Core/State.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@ -230,21 +231,23 @@ void SaveToBuffer(std::vector<u8>& buffer)
|
|||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return state number not in map
|
namespace
|
||||||
static int GetEmptySlot(std::map<double, int> m)
|
{
|
||||||
|
struct SlotWithTimestamp
|
||||||
|
{
|
||||||
|
int slot;
|
||||||
|
double timestamp;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// returns first slot number not in the vector, or -1 if all are in the vector
|
||||||
|
static int GetEmptySlot(const std::vector<SlotWithTimestamp>& used_slots)
|
||||||
{
|
{
|
||||||
for (int i = 1; i <= (int)NUM_STATES; i++)
|
for (int i = 1; i <= (int)NUM_STATES; i++)
|
||||||
{
|
{
|
||||||
bool found = false;
|
const auto it = std::find_if(used_slots.begin(), used_slots.end(),
|
||||||
for (auto& p : m)
|
[i](const SlotWithTimestamp& slot) { return slot.slot == i; });
|
||||||
{
|
if (it == used_slots.end())
|
||||||
if (p.second == i)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
@ -265,27 +268,29 @@ static double GetSystemTimeAsDouble()
|
|||||||
static std::string SystemTimeAsDoubleToString(double time)
|
static std::string SystemTimeAsDoubleToString(double time)
|
||||||
{
|
{
|
||||||
// revert adjustments from GetSystemTimeAsDouble() to get a normal Unix timestamp again
|
// revert adjustments from GetSystemTimeAsDouble() to get a normal Unix timestamp again
|
||||||
time_t seconds = (time_t)time + DOUBLE_TIME_OFFSET;
|
time_t seconds = static_cast<time_t>(time) + DOUBLE_TIME_OFFSET;
|
||||||
tm* localTime = localtime(&seconds);
|
errno = 0;
|
||||||
|
tm* local_time = localtime(&seconds);
|
||||||
|
if (errno != 0 || !local_time)
|
||||||
|
return "";
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
wchar_t tmp[32] = {};
|
wchar_t tmp[32] = {};
|
||||||
wcsftime(tmp, std::size(tmp), L"%x %X", localTime);
|
wcsftime(tmp, std::size(tmp), L"%x %X", local_time);
|
||||||
return WStringToUTF8(tmp);
|
return WStringToUTF8(tmp);
|
||||||
#else
|
#else
|
||||||
char tmp[32] = {};
|
char tmp[32] = {};
|
||||||
strftime(tmp, sizeof(tmp), "%x %X", localTime);
|
strftime(tmp, sizeof(tmp), "%x %X", local_time);
|
||||||
return tmp;
|
return tmp;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string MakeStateFilename(int number);
|
static std::string MakeStateFilename(int number);
|
||||||
|
|
||||||
// read state timestamps
|
static std::vector<SlotWithTimestamp> GetUsedSlotsWithTimestamp()
|
||||||
static std::map<double, int> GetSavedStates()
|
|
||||||
{
|
{
|
||||||
|
std::vector<SlotWithTimestamp> result;
|
||||||
StateHeader header;
|
StateHeader header;
|
||||||
std::map<double, int> m;
|
|
||||||
for (int i = 1; i <= (int)NUM_STATES; i++)
|
for (int i = 1; i <= (int)NUM_STATES; i++)
|
||||||
{
|
{
|
||||||
std::string filename = MakeStateFilename(i);
|
std::string filename = MakeStateFilename(i);
|
||||||
@ -293,17 +298,16 @@ static std::map<double, int> GetSavedStates()
|
|||||||
{
|
{
|
||||||
if (ReadHeader(filename, header))
|
if (ReadHeader(filename, header))
|
||||||
{
|
{
|
||||||
double d = GetSystemTimeAsDouble() - header.legacy_header.time;
|
result.emplace_back(SlotWithTimestamp{.slot = i, .timestamp = header.legacy_header.time});
|
||||||
|
|
||||||
// increase time until unique value is obtained
|
|
||||||
while (m.find(d) != m.end())
|
|
||||||
d += .001;
|
|
||||||
|
|
||||||
m.emplace(d, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CompareTimestamp(const SlotWithTimestamp& lhs, const SlotWithTimestamp& rhs)
|
||||||
|
{
|
||||||
|
return lhs.timestamp < rhs.timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CompressBufferToFile(const u8* raw_buffer, u64 size, File::IOFile& f)
|
static void CompressBufferToFile(const u8* raw_buffer, u64 size, File::IOFile& f)
|
||||||
@ -954,33 +958,37 @@ void Load(int slot)
|
|||||||
|
|
||||||
void LoadLastSaved(int i)
|
void LoadLastSaved(int i)
|
||||||
{
|
{
|
||||||
std::map<double, int> savedStates = GetSavedStates();
|
if (i <= 0)
|
||||||
|
|
||||||
if (i > (int)savedStates.size())
|
|
||||||
Core::DisplayMessage("State doesn't exist", 2000);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
std::map<double, int>::iterator it = savedStates.begin();
|
Core::DisplayMessage("State doesn't exist", 2000);
|
||||||
std::advance(it, i - 1);
|
return;
|
||||||
Load(it->second);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<SlotWithTimestamp> used_slots = GetUsedSlotsWithTimestamp();
|
||||||
|
if (static_cast<size_t>(i) > used_slots.size())
|
||||||
|
{
|
||||||
|
Core::DisplayMessage("State doesn't exist", 2000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stable_sort(used_slots.begin(), used_slots.end(), CompareTimestamp);
|
||||||
|
Load((used_slots.end() - i)->slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
// must wait for state to be written because it must know if all slots are taken
|
// must wait for state to be written because it must know if all slots are taken
|
||||||
void SaveFirstSaved()
|
void SaveFirstSaved()
|
||||||
{
|
{
|
||||||
std::map<double, int> savedStates = GetSavedStates();
|
std::vector<SlotWithTimestamp> used_slots = GetUsedSlotsWithTimestamp();
|
||||||
|
if (used_slots.size() < NUM_STATES)
|
||||||
// save to an empty slot
|
|
||||||
if (savedStates.size() < NUM_STATES)
|
|
||||||
Save(GetEmptySlot(savedStates), true);
|
|
||||||
// overwrite the oldest state
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
std::map<double, int>::iterator it = savedStates.begin();
|
// save to an empty slot
|
||||||
std::advance(it, savedStates.size() - 1);
|
Save(GetEmptySlot(used_slots), true);
|
||||||
Save(it->second, true);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// overwrite the oldest state
|
||||||
|
std::stable_sort(used_slots.begin(), used_slots.end(), CompareTimestamp);
|
||||||
|
Save(used_slots.front().slot, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the last state before loading the state
|
// Load the last state before loading the state
|
||||||
|
Loading…
x
Reference in New Issue
Block a user