CTitleStateIntro_patches: display error message on corrupted save data

TitleMenuRemoveContinueOnCorruptSaveMidAsmHook by @DeaTh-G

Co-Authored-By: DeaTh-G <55578911+DeaTh-G@users.noreply.github.com>
This commit is contained in:
Hyper 2025-01-18 18:58:29 +00:00
parent 1bbdf3ca5a
commit d14d4ce71f
7 changed files with 85 additions and 3 deletions

View file

@ -9,6 +9,7 @@ public:
static inline bool s_isMissingDLC;
static inline bool s_isLoading;
static inline bool s_isWerehog;
static inline bool s_isSaveDataCorrupt;
static inline ELanguage s_language;

View file

@ -342,6 +342,20 @@ std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_lo
{ ELanguage::Italian, "Sei sicuro di voler uscire?" }
}
},
{
// Notes: message appears when the SYS-DATA is corrupted (mismatching file size).
// To make this occur, open the file in any editor and just remove a large chunk of data.
// Do not localise this unless absolutely necessary, these strings are from the XEX.
"Title_Message_SaveDataCorrupt",
{
{ ELanguage::English, "The save file appears to be\ncorrupted and cannot be loaded." },
{ ELanguage::Japanese, "ゲームデータの読み込みに失敗しました。\nこのまま続けるとゲームデータをセーブすることはできません" },
{ ELanguage::German, "Diese Speicherdatei ist beschädigt\nund kann nicht geladen werden." },
{ ELanguage::French, "Le fichier de sauvegarde semble être\nendommagé et ne peut être chargé." },
{ ELanguage::Spanish, "El archivo parece estar dañado\ny no se puede cargar." },
{ ELanguage::Italian, "I file di salvataggio sembrano danneggiati\ne non possono essere caricati." }
}
},
{
"Common_On",
{

View file

@ -49,8 +49,6 @@ void WerehogBattleMusicMidAsmHook(PPCRegister& r11)
r11.u8 = 3;
}
void StorageDevicePromptMidAsmHook() {}
/* Hook function that gets the game region
and force result to zero for Japanese
to display the correct logos. */

View file

@ -69,6 +69,8 @@ PPC_FUNC(sub_824E5170)
if (pSaveIcon->m_IsVisible)
{
App::s_isSaveDataCorrupt = false;
if (!m_isSavedAchievementData)
{
LOGN("Saving achievements...");

View file

@ -2,14 +2,21 @@
#include <locale/locale.h>
#include <ui/fader.h>
#include <ui/message_window.h>
#include <user/paths.h>
#include <app.h>
static bool g_quitMessageOpen = false;
static bool g_quitMessageFaderBegun = false;
static int g_quitMessageResult = -1;
static std::atomic<bool> g_corruptSaveMessageOpen = false;
static int g_corruptSaveMessageResult = -1;
static bool ProcessQuitMessage()
{
if (g_corruptSaveMessageOpen)
return false;
if (!g_quitMessageOpen)
return false;
@ -37,6 +44,49 @@ static bool ProcessQuitMessage()
return true;
}
static bool ProcessCorruptSaveMessage()
{
if (!g_corruptSaveMessageOpen)
return false;
if (MessageWindow::Open(Localise("Title_Message_SaveDataCorrupt"), &g_corruptSaveMessageResult) == MSG_CLOSED)
{
g_corruptSaveMessageOpen = false;
g_corruptSaveMessageOpen.notify_one();
g_corruptSaveMessageResult = -1;
}
return true;
}
void StorageDevicePromptMidAsmHook() {}
// Save data validation hook.
PPC_FUNC_IMPL(__imp__sub_822C4330);
PPC_FUNC(sub_822C4330)
{
std::error_code ec;
auto saveFileSize = std::filesystem::file_size(GetSaveFilePath(true), ec);
auto expectedSize = ctx.r5.u32;
auto expectedSizeAdd = *(be<uint32_t>*)g_memory.Translate(0x83262110);
// TODO: check for backups here and restore them?
if (saveFileSize != expectedSize + expectedSizeAdd)
{
App::s_isSaveDataCorrupt = true;
g_corruptSaveMessageOpen = true;
g_corruptSaveMessageOpen.wait(true);
ctx.r3.u32 = 0;
return;
}
ctx.r3.u32 = 1;
}
// SWA::CTitleStateIntro::Update
PPC_FUNC_IMPL(__imp__sub_82587E50);
PPC_FUNC(sub_82587E50)
@ -47,7 +97,7 @@ PPC_FUNC(sub_82587E50)
{
__imp__sub_82587E50(ctx, base);
}
else
else if (!ProcessCorruptSaveMessage())
{
auto pInputState = SWA::CInputState::GetInstance();

View file

@ -56,6 +56,10 @@ PPC_FUNC(sub_825882B8)
auto isOptionsIndex = pTitleState->m_pMember->m_pTitleMenu->m_CursorIndex == 2;
auto isInstallIndex = pTitleState->m_pMember->m_pTitleMenu->m_CursorIndex == 3;
// Always default to New Game with corrupted save data.
if (App::s_isSaveDataCorrupt && pTitleState->m_pMember->m_pTitleMenu->m_CursorIndex == 1)
pTitleState->m_pMember->m_pTitleMenu->m_CursorIndex = 0;
if (!OptionsMenu::s_isVisible && isOptionsIndex)
{
if (OptionsMenu::s_isRestartRequired)
@ -92,6 +96,14 @@ PPC_FUNC(sub_825882B8)
}
}
void TitleMenuRemoveContinueOnCorruptSaveMidAsmHook(PPCRegister& r3)
{
if (!App::s_isSaveDataCorrupt)
return;
r3.u64 = 0;
}
void TitleMenuRemoveStorageDeviceOptionMidAsmHook(PPCRegister& r11)
{
r11.u32 = 0;

View file

@ -663,3 +663,8 @@ registers = ["r3"]
name = "InspireSubtitleMidAsmHook"
address = 0x82B949B0
registers = ["r3"]
[[midasm_hook]]
name = "TitleMenuRemoveContinueOnCorruptSaveMidAsmHook"
address = 0x82585470
registers = ["r3"]