Pad: Fix unconditional memory card replug on load state

This commit is contained in:
Stenzek 2024-03-29 12:34:42 +10:00
parent e54ad1956a
commit c41563c7dc
No known key found for this signature in database
3 changed files with 52 additions and 27 deletions

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "memory_card.h"
@ -65,6 +65,19 @@ bool MemoryCard::DoState(StateWrapper& sw)
return !sw.HasError();
}
void MemoryCard::CopyState(const MemoryCard* src)
{
DebugAssert(m_data == src->m_data);
m_state = src->m_state;
m_FLAG.bits = src->m_FLAG.bits;
m_address = src->m_address;
m_sector_offset = src->m_sector_offset;
m_checksum = src->m_checksum;
m_last_byte = src->m_last_byte;
m_changed = src->m_changed;
}
void MemoryCard::ResetTransferState()
{
m_state = State::Idle;

View file

@ -30,6 +30,7 @@ public:
void Reset();
bool DoState(StateWrapper& sw);
void CopyState(const MemoryCard* src);
void ResetTransferState();
bool Transfer(const u8 data_in, u8* data_out);

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "pad.h"
@ -19,6 +19,8 @@
#include "common/fifo_queue.h"
#include "common/log.h"
#include "IconsFontAwesome5.h"
#include <array>
#include <memory>
@ -257,16 +259,16 @@ bool Pad::DoStateMemcard(StateWrapper& sw, u32 i, bool is_memory_state)
if (card_present_in_state && !s_memory_cards[i] && g_settings.load_devices_from_save_states)
{
Host::AddFormattedOSDMessage(
20.0f,
TRANSLATE("OSDMessage", "Memory card %u present in save state but not in system. Creating temporary card."),
i + 1u);
Host::AddIconOSDMessage(
fmt::format("card_load_warning_{}", i), ICON_FA_SD_CARD,
fmt::format(
TRANSLATE_FS("OSDMessage", "Memory card {} present in save state but not in system. Creating temporary card."),
i + 1u),
Host::OSD_ERROR_DURATION);
s_memory_cards[i] = MemoryCard::Create();
}
MemoryCard* card_ptr = s_memory_cards[i].get();
std::unique_ptr<MemoryCard> card_from_state;
if (card_present_in_state)
{
if (sw.IsReading() && !g_settings.load_devices_from_save_states)
@ -284,22 +286,24 @@ bool Pad::DoStateMemcard(StateWrapper& sw, u32 i, bool is_memory_state)
if (sw.IsWriting())
return true; // all done as far as writes concerned.
if (card_from_state)
if (card_ptr != s_memory_cards[i].get())
{
if (s_memory_cards[i])
{
if (s_memory_cards[i]->GetData() == card_from_state->GetData())
if (s_memory_cards[i]->GetData() == card_ptr->GetData())
{
card_from_state->SetFilename(s_memory_cards[i]->GetFilename());
s_memory_cards[i] = std::move(card_from_state);
Log_DevFmt("Card {} data matches, copying state", i + 1u);
s_memory_cards[i]->CopyState(card_ptr);
}
else
{
Host::AddFormattedOSDMessage(
20.0f,
TRANSLATE("OSDMessage",
"Memory card %u from save state does match current card data. Simulating replugging."),
i + 1u);
Host::AddIconOSDMessage(
fmt::format("card_load_warning_{}", i), ICON_FA_SD_CARD,
fmt::format(
TRANSLATE_FS("OSDMessage",
"Memory card {} from save state does match current card data. Simulating replugging."),
i + 1u),
Host::OSD_WARNING_DURATION);
// this is a potentially serious issue - some games cache info from memcards and jumping around
// with savestates can lead to card corruption on the next save attempts (and may not be obvious
@ -307,15 +311,17 @@ bool Pad::DoStateMemcard(StateWrapper& sw, u32 i, bool is_memory_state)
// for the game to decide it was removed and purge its cache. Once implemented, this could be
// described as deferred re-plugging in the log.
Log_WarningPrintf("Memory card %u data mismatch. Using current data via instant-replugging.", i + 1u);
Log_WarningFmt("Memory card {} data mismatch. Using current data via instant-replugging.", i + 1u);
s_memory_cards[i]->Reset();
}
}
else
{
Host::AddFormattedOSDMessage(
20.0f, TRANSLATE("OSDMessage", "Memory card %u present in save state but not in system. Ignoring card."),
i + 1u);
Host::AddIconOSDMessage(
fmt::format("card_load_warning_{}", i), ICON_FA_SD_CARD,
fmt::format(
TRANSLATE_FS("OSDMessage", "Memory card {} present in save state but not in system. Ignoring card."), i + 1u),
Host::OSD_ERROR_DURATION);
}
return true;
@ -325,16 +331,21 @@ bool Pad::DoStateMemcard(StateWrapper& sw, u32 i, bool is_memory_state)
{
if (g_settings.load_devices_from_save_states)
{
Host::AddFormattedOSDMessage(
20.0f, TRANSLATE("OSDMessage", "Memory card %u present in system but not in save state. Removing card."),
i + 1u);
Host::AddIconOSDMessage(
fmt::format("card_load_warning_{}", i), ICON_FA_SD_CARD,
fmt::format(
TRANSLATE_FS("OSDMessage", "Memory card {} present in system but not in save state. Removing card."), i + 1u),
Host::OSD_ERROR_DURATION);
s_memory_cards[i].reset();
}
else
{
Host::AddFormattedOSDMessage(
20.0f, TRANSLATE("OSDMessage", "Memory card %u present in system but not in save state. Replugging card."),
i + 1u);
Host::AddIconOSDMessage(
fmt::format("card_load_warning_{}", i), ICON_FA_SD_CARD,
fmt::format(
TRANSLATE_FS("OSDMessage", "Memory card {} present in system but not in save state. Replugging card."),
i + 1u),
Host::OSD_WARNING_DURATION);
s_memory_cards[i]->Reset();
}
}