diff --git a/Runtime/CMemoryCardSys.cpp b/Runtime/CMemoryCardSys.cpp index 1f97829bf..c2ef32f86 100644 --- a/Runtime/CMemoryCardSys.cpp +++ b/Runtime/CMemoryCardSys.cpp @@ -336,6 +336,9 @@ ECardResult CMemoryCardSys::CCardFileInfo::WriteFile() { } ECardResult CMemoryCardSys::CCardFileInfo::CloseFile() { return CMemoryCardSys::CloseFile(m_handle); } +kabufuda::SystemString CMemoryCardSys::_GetDolphinCardPath(kabufuda::ECardSlot slot) { + return g_CardImagePaths[static_cast(slot)]; +} void CMemoryCardSys::_ResolveDolphinCardPath(const hecl::CVar* cv, kabufuda::ECardSlot slot) { #if CARD_UCS2 @@ -559,19 +562,31 @@ void CMemoryCardSys::CommitToDisk(kabufuda::ECardSlot port) { card.commit(); } -kabufuda::SystemString CMemoryCardSys::CreateDolphinCard(kabufuda::ECardSlot slot) { - kabufuda::SystemString path = _CreateDolphinCard(slot); +bool CMemoryCardSys::CreateDolphinCard(kabufuda::ECardSlot slot) { + kabufuda::SystemString path = + _CreateDolphinCard(slot, slot == kabufuda::ECardSlot::SlotA ? mc_dolphinAPath->hasDefaultValue() + : mc_dolphinBPath->hasDefaultValue()); if (CardProbe(slot).x0_error != ECardResult::READY) { - return {}; + return false; } MountCard(slot); FormatCard(slot); kabufuda::Card& card = g_CardStates[int(slot)]; card.waitForCompletion(); - return path; + return true; } +void CMemoryCardSys::_ResetCVar(kabufuda::ECardSlot slot) { + switch(slot) { + case kabufuda::ECardSlot::SlotA: + mc_dolphinAPath->fromLiteral(""); + break; + case kabufuda::ECardSlot::SlotB: + mc_dolphinBPath->fromLiteral(""); + break; + } +} void CMemoryCardSys::Shutdown() { UnmountCard(kabufuda::ECardSlot::SlotA); UnmountCard(kabufuda::ECardSlot::SlotB); diff --git a/Runtime/CMemoryCardSys.hpp b/Runtime/CMemoryCardSys.hpp index 2dedf83f9..52bce56d6 100644 --- a/Runtime/CMemoryCardSys.hpp +++ b/Runtime/CMemoryCardSys.hpp @@ -67,10 +67,12 @@ class CMemoryCardSys { rstl::reserved_vector x30_scanCategoryCounts; public: + static void _ResetCVar(kabufuda::ECardSlot slot); static void _ResolveDolphinCardPath(const hecl::CVar* cv, kabufuda::ECardSlot slot); static kabufuda::SystemString ResolveDolphinCardPath(kabufuda::ECardSlot slot); - static kabufuda::SystemString CreateDolphinCard(kabufuda::ECardSlot slot); - static kabufuda::SystemString _CreateDolphinCard(kabufuda::ECardSlot slot); + static bool CreateDolphinCard(kabufuda::ECardSlot slot); + static kabufuda::SystemString _GetDolphinCardPath(kabufuda::ECardSlot slot); + static kabufuda::SystemString _CreateDolphinCard(kabufuda::ECardSlot slot, bool dolphin); using ECardResult = kabufuda::ECardResult; struct CardResult { diff --git a/Runtime/CMemoryCardSysNix.cpp b/Runtime/CMemoryCardSysNix.cpp index c1afd706b..8354496e9 100644 --- a/Runtime/CMemoryCardSysNix.cpp +++ b/Runtime/CMemoryCardSysNix.cpp @@ -31,27 +31,39 @@ kabufuda::SystemString CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlo return {}; } -kabufuda::SystemString CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot slot) { +kabufuda::SystemString CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot slot, bool dolphin) { if (g_Main->IsUSA() && !g_Main->IsTrilogy()) { - const char* home = getenv("HOME"); - if (!home || home[0] != '/') - return {}; - const char* dataHome = getenv("XDG_DATA_HOME"); + if (dolphin) { + const char* home = getenv("HOME"); + if (!home || home[0] != '/') + return {}; + const char* dataHome = getenv("XDG_DATA_HOME"); - /* XDG-selected data path */ - kabufuda::SystemString path = - ((dataHome && dataHome[0] == '/') ? dataHome : hecl::SystemString(home)) + "/.local/share/dolphin-emu/GC"; + /* XDG-selected data path */ + kabufuda::SystemString path = + ((dataHome && dataHome[0] == '/') ? dataHome : hecl::SystemString(home)) + "/.local/share/dolphin-emu/GC"; - if (hecl::RecursiveMakeDir(path.c_str()) < 0) - return {}; + if (hecl::RecursiveMakeDir(path.c_str()) < 0) + return {}; - path += fmt::format(FMT_STRING("/MemoryCard{:c}.USA.raw"), slot == kabufuda::ECardSlot::SlotA ? 'A' : 'B'); - const auto fp = hecl::FopenUnique(path.c_str(), "wb"); - if (fp == nullptr) { - return {}; + path += fmt::format(FMT_STRING("/MemoryCard{:c}.USA.raw"), slot == kabufuda::ECardSlot::SlotA ? 'A' : 'B'); + const auto fp = hecl::FopenUnique(path.c_str(), "wb"); + if (fp != nullptr) { + return path; + } + } else { + kabufuda::SystemString path = _GetDolphinCardPath(slot); + hecl::SanitizePath(path); + if (path.find('/') == kabufuda::SystemString::npos) { + path = hecl::GetcwdStr() + _SYS_STR("/") + _GetDolphinCardPath(slot); + } + hecl::SystemString tmpPath = path.substr(0, path.find_last_of(_SYS_STR("/"))); + hecl::RecursiveMakeDir(tmpPath.c_str()); + const auto fp = hecl::FopenUnique(path.c_str(), "wb"); + if (fp) { + return path; + } } - - return path; } return {}; } diff --git a/Runtime/CMemoryCardSysOSX.cpp b/Runtime/CMemoryCardSysOSX.cpp index 1c5628e5c..7f8813c4d 100644 --- a/Runtime/CMemoryCardSysOSX.cpp +++ b/Runtime/CMemoryCardSysOSX.cpp @@ -22,24 +22,38 @@ kabufuda::SystemString CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlo return {}; } -kabufuda::SystemString CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot slot) { +kabufuda::SystemString CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot slot, bool dolphin) { if (g_Main->IsUSA() && !g_Main->IsTrilogy()) { - const char* home = getenv("HOME"); - if (!home) - return {}; + if (dolphin) { + const char* home = getenv("HOME"); + if (!home) + return {}; - kabufuda::SystemString path = home; - path += "/Library/Application Support/Dolphin/GC"; - if (hecl::RecursiveMakeDir(path.c_str()) < 0) - return {}; + kabufuda::SystemString path = home; + path += "/Library/Application Support/Dolphin/GC"; + if (hecl::RecursiveMakeDir(path.c_str()) < 0) + return {}; - path += fmt::format(FMT_STRING("/MemoryCard{:c}.USA.raw"), slot == kabufuda::ECardSlot::SlotA ? 'A' : 'B'); - const auto fp = hecl::FopenUnique(path.c_str(), "wb"); - if (fp == nullptr) { - return {}; + path += fmt::format(FMT_STRING("/MemoryCard{:c}.USA.raw"), slot == kabufuda::ECardSlot::SlotA ? 'A' : 'B'); + const auto fp = hecl::FopenUnique(path.c_str(), "wb"); + if (fp == nullptr) { + return {}; + } + + return path; + } else { + kabufuda::SystemString path = _GetDolphinCardPath(slot); + hecl::SanitizePath(path); + if (path.find('/') == kabufuda::SystemString::npos) { + path = hecl::GetcwdStr() + _SYS_STR("/") + _GetDolphinCardPath(slot); + } + hecl::SystemString tmpPath = path.substr(0, path.find_last_of(_SYS_STR("/"))); + hecl::RecursiveMakeDir(tmpPath.c_str()); + const auto fp = hecl::FopenUnique(path.c_str(), "wb"); + if (fp) { + return path; + } } - - return path; } return {}; } diff --git a/Runtime/CMemoryCardSysWin.cpp b/Runtime/CMemoryCardSysWin.cpp index c32d83924..943d364cf 100644 --- a/Runtime/CMemoryCardSysWin.cpp +++ b/Runtime/CMemoryCardSysWin.cpp @@ -14,53 +14,67 @@ using namespace Windows::Storage; /* Partial path-selection logic from * https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/UICommon/UICommon.cpp * Modified to not use dolphin-binary-relative paths. */ -kabufuda::SystemString CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlot slot) { +kabufuda::SystemString CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlot slot, bool dolphin) { if (g_Main->IsUSA() && !g_Main->IsTrilogy()) { + if (dolphin) { #if !WINDOWS_STORE - /* Detect where the User directory is. There are two different cases - * 1. HKCU\Software\Dolphin Emulator\UserConfigPath exists - * -> Use this as the user directory path - * 2. My Documents exists - * -> Use My Documents\Dolphin Emulator as the User directory path - */ + /* Detect where the User directory is. There are two different cases + * 1. HKCU\Software\Dolphin Emulator\UserConfigPath exists + * -> Use this as the user directory path + * 2. My Documents exists + * -> Use My Documents\Dolphin Emulator as the User directory path + */ - /* Check our registry keys */ - HKEY hkey; - kabufuda::SystemChar configPath[MAX_PATH] = {0}; - if (RegOpenKeyEx(HKEY_CURRENT_USER, _SYS_STR("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE, &hkey) == - ERROR_SUCCESS) { - DWORD size = MAX_PATH; - if (RegQueryValueEx(hkey, _SYS_STR("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath, &size) != - ERROR_SUCCESS) - configPath[0] = 0; - RegCloseKey(hkey); - } + /* Check our registry keys */ + HKEY hkey; + kabufuda::SystemChar configPath[MAX_PATH] = {0}; + if (RegOpenKeyEx(HKEY_CURRENT_USER, _SYS_STR("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE, &hkey) == + ERROR_SUCCESS) { + DWORD size = MAX_PATH; + if (RegQueryValueEx(hkey, _SYS_STR("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath, &size) != + ERROR_SUCCESS) + configPath[0] = 0; + RegCloseKey(hkey); + } - /* Get My Documents path in case we need it. */ - kabufuda::SystemChar my_documents[MAX_PATH]; - bool my_documents_found = - SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents)); + /* Get My Documents path in case we need it. */ + kabufuda::SystemChar my_documents[MAX_PATH]; + bool my_documents_found = + SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents)); - kabufuda::SystemString path; - if (configPath[0]) /* Case 1 */ - path = configPath; - else if (my_documents_found) /* Case 2 */ - path = kabufuda::SystemString(my_documents) + _SYS_STR("/Dolphin Emulator"); - else /* Unable to find */ - return {}; + kabufuda::SystemString path; + if (configPath[0]) /* Case 1 */ + path = configPath; + else if (my_documents_found) /* Case 2 */ + path = kabufuda::SystemString(my_documents) + _SYS_STR("/Dolphin Emulator"); + else /* Unable to find */ + return {}; #else - StorageFolder ^ localFolder = ApplicationData::Current->LocalFolder; - kabufuda::SystemString path(localFolder->Path->Data()); + StorageFolder ^ localFolder = ApplicationData::Current->LocalFolder; + kabufuda::SystemString path(localFolder->Path->Data()); #endif - path += fmt::format(FMT_STRING(_SYS_STR("/GC/MemoryCard{}.USA.raw")), - slot == kabufuda::ECardSlot::SlotA ? _SYS_STR('A') : _SYS_STR('B')); + path += fmt::format(FMT_STRING(_SYS_STR("/GC/MemoryCard{}.USA.raw")), + slot == kabufuda::ECardSlot::SlotA ? _SYS_STR('A') : _SYS_STR('B')); - hecl::Sstat theStat; - if (hecl::Stat(path.c_str(), &theStat) || !S_ISREG(theStat.st_mode)) - return {}; + hecl::Sstat theStat; + if (hecl::Stat(path.c_str(), &theStat) || !S_ISREG(theStat.st_mode)) + return {}; - return path; + return path; + } else { + kabufuda::SystemString path = _GetDolphinCardPath(slot); + hecl::SanitizePath(path); + if (path.find('/') == kabufuda::SystemString::npos) { + path = hecl::GetcwdStr() + _SYS_STR("/") + _GetDolphinCardPath(slot); + } + hecl::SystemString tmpPath = path.substr(0, path.find_last_of(_SYS_STR("/"))); + hecl::RecursiveMakeDir(tmpPath.c_str()); + const auto fp = hecl::FopenUnique(path.c_str(), "wb"); + if (fp) { + return path; + } + } } return {}; } @@ -69,10 +83,10 @@ kabufuda::SystemString CMemoryCardSys::_CreateDolphinCard(kabufuda::ECardSlot sl if (g_Main->IsUSA() && !g_Main->IsTrilogy()) { #if !WINDOWS_STORE /* Detect where the User directory is. There are two different cases - * 1. HKCU\Software\Dolphin Emulator\UserConfigPath exists - * -> Use this as the user directory path - * 2. My Documents exists - * -> Use My Documents\Dolphin Emulator as the User directory path + * 1. HKCU\Software\Dolphin Emulator\UserConfigPath exists + * -> Use this as the user directory path + * 2. My Documents exists + * -> Use My Documents\Dolphin Emulator as the User directory path */ /* Check our registry keys */ diff --git a/Runtime/MP1/CSaveGameScreen.cpp b/Runtime/MP1/CSaveGameScreen.cpp index d55d8cba8..9bc6de305 100644 --- a/Runtime/MP1/CSaveGameScreen.cpp +++ b/Runtime/MP1/CSaveGameScreen.cpp @@ -131,6 +131,9 @@ bool CSaveGameScreen::PumpLoad() { } CSaveGameScreen::EUIType CSaveGameScreen::SelectUIType() const { + if (x10_uiType == EUIType::CreateDolphinCardFailed) { + return x10_uiType; + } if (x6c_cardDriver->x10_state == EState::NoCard) { return EUIType::NoCardFound; } @@ -312,6 +315,12 @@ void CSaveGameScreen::SetUIText() { opt1 = 15; // No } break; + case EUIType::CreateDolphinCardFailed: + msgAStr = u"Attempt to create Dolphin Card failed!\n"; + msgBStr = u"CVars have been reset to defaults.\nMetaforce will use Dolphin's memory cards if available\n"; + opt0 = -2; + opt0Str = u"Press &image=SI,1.0,0.68,05AF9CAA; to proceed.\n"; + break; default: break; } @@ -392,7 +401,12 @@ void CSaveGameScreen::DoAdvance([[maybe_unused]] CGuiTableGroup* caller) { sfx = x84_navConfirmSfx; } else if (userSel == 2 && x10_uiType == EUIType::NoCardFound) { /* Create Dolphin Card */ - CMemoryCardSys::CreateDolphinCard(kabufuda::ECardSlot::SlotA); + if (!CMemoryCardSys::CreateDolphinCard(kabufuda::ECardSlot::SlotA)) { + x10_uiType = EUIType::CreateDolphinCardFailed; + sfx = x8c_navBackSfx; + x91_uiTextDirty = true; + break; + } ResetCardDriver(); sfx = x84_navConfirmSfx; } @@ -556,6 +570,15 @@ void CSaveGameScreen::DoAdvance([[maybe_unused]] CGuiTableGroup* caller) { } } break; + case EUIType::CreateDolphinCardFailed: { + if (userSel == 0) { + CMemoryCardSys::_ResetCVar(kabufuda::ECardSlot::SlotA); + CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlot::SlotA); + ResetCardDriver(); + x10_uiType = EUIType::Empty; + sfx = x84_navConfirmSfx; + } + } break; default: break; diff --git a/Runtime/MP1/CSaveGameScreen.hpp b/Runtime/MP1/CSaveGameScreen.hpp index 635fd3c6c..9b17658d7 100644 --- a/Runtime/MP1/CSaveGameScreen.hpp +++ b/Runtime/MP1/CSaveGameScreen.hpp @@ -41,7 +41,9 @@ public: ProgressWillBeLost = 13, NotOriginalCard = 14, AllDataWillBeLost = 15, - SaveReady = 16 + SaveReady = 16, + // Metaforce Addition + CreateDolphinCardFailed }; bool IsHiddenFromFrontEnd() const {