diff --git a/Source/Core/Common/StringUtil.cpp b/Source/Core/Common/StringUtil.cpp index 3afb09873f..c44f3fa7b1 100644 --- a/Source/Core/Common/StringUtil.cpp +++ b/Source/Core/Common/StringUtil.cpp @@ -322,6 +322,13 @@ bool SplitPath(std::string_view full_path, std::string* path, std::string* filen return true; } +std::string PathToFileName(std::string_view path) +{ + std::string file_name, extension; + SplitPath(path, nullptr, &file_name, &extension); + return file_name + extension; +} + void BuildCompleteFilename(std::string& complete_filename, std::string_view path, std::string_view filename) { diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index 211c381abf..969c6e9ea1 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -159,6 +159,8 @@ std::string JoinStrings(const std::vector& strings, const std::stri bool SplitPath(std::string_view full_path, std::string* path, std::string* filename, std::string* extension); +std::string PathToFileName(std::string_view path); + void BuildCompleteFilename(std::string& complete_filename, std::string_view path, std::string_view filename); diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index 9b58f580e1..4dbe7a2f9d 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -45,6 +45,7 @@ #include "Core/Movie.h" #include "Core/NetPlayProto.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/WiiRoot.h" #include "DiscIO/Enums.h" @@ -439,7 +440,10 @@ bool BootCore(std::unique_ptr boot, const WindowSystemInfo& wsi) // Ensure any new settings are written to the SYSCONF if (StartUp.bWii) + { + Core::BackupWiiSettings(); ConfigLoaders::SaveToSYSCONF(Config::LayerType::Meta); + } const bool load_ipl = !StartUp.bWii && !StartUp.bHLE_BS2 && std::holds_alternative(boot->parameters); @@ -487,6 +491,7 @@ static void RestoreSYSCONF() void RestoreConfig() { + Core::RestoreWiiSettings(Core::RestoreReason::EmulationEnd); RestoreSYSCONF(); Config::ClearCurrentRunLayer(); Config::RemoveLayer(Config::LayerType::Movie); diff --git a/Source/Core/Core/WiiRoot.cpp b/Source/Core/Core/WiiRoot.cpp index c5caf3b7b7..3b7a17ab97 100644 --- a/Source/Core/Core/WiiRoot.cpp +++ b/Source/Core/Core/WiiRoot.cpp @@ -16,6 +16,8 @@ #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/NandPaths.h" +#include "Common/StringUtil.h" +#include "Core/CommonTitles.h" #include "Core/ConfigManager.h" #include "Core/HW/WiiSave.h" #include "Core/IOS/ES/ES.h" @@ -32,6 +34,38 @@ namespace FS = IOS::HLE::FS; static std::string s_temp_wii_root; +static bool CopyBackupFile(const std::string& path_from, const std::string& path_to) +{ + if (!File::Exists(path_from)) + return false; + + return File::Copy(path_from, path_to); +} + +static void DeleteBackupFile(const std::string& file_name) +{ + File::Delete(File::GetUserPath(D_BACKUP_IDX) + DIR_SEP + file_name); +} + +static void BackupFile(const std::string& path_in_nand) +{ + const std::string file_name = PathToFileName(path_in_nand); + const std::string original_path = File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP + path_in_nand; + const std::string backup_path = File::GetUserPath(D_BACKUP_IDX) + DIR_SEP + file_name; + + CopyBackupFile(original_path, backup_path); +} + +static void RestoreFile(const std::string& path_in_nand) +{ + const std::string file_name = PathToFileName(path_in_nand); + const std::string original_path = File::GetUserPath(D_WIIROOT_IDX) + DIR_SEP + path_in_nand; + const std::string backup_path = File::GetUserPath(D_BACKUP_IDX) + DIR_SEP + file_name; + + if (CopyBackupFile(backup_path, original_path)) + DeleteBackupFile(file_name); +} + static void CopySave(FS::FileSystem* source, FS::FileSystem* dest, const u64 title_id) { dest->CreateFullPath(IOS::PID_KERNEL, IOS::PID_KERNEL, Common::GetTitleDataPath(title_id) + '/', @@ -173,6 +207,29 @@ void ShutdownWiiRoot() } } +void BackupWiiSettings() +{ + // Back up files which Dolphin can modify at boot, so that we can preserve the original contents. + // For SYSCONF, the backup is only needed in case Dolphin crashes or otherwise exists unexpectedly + // during emulation, since the config system will restore the SYSCONF settings at emulation end. + // For setting.txt, there is no other code that restores the original values for us. + + BackupFile(Common::GetTitleDataPath(Titles::SYSTEM_MENU) + "/" WII_SETTING); + BackupFile("/shared2/sys/SYSCONF"); +} + +void RestoreWiiSettings(RestoreReason reason) +{ + RestoreFile(Common::GetTitleDataPath(Titles::SYSTEM_MENU) + "/" WII_SETTING); + + // We must not restore the SYSCONF backup when ending emulation cleanly, since the user may have + // edited the SYSCONF file in the NAND using the emulated software (e.g. the Wii Menu settings). + if (reason == RestoreReason::CrashRecovery) + RestoreFile("/shared2/sys/SYSCONF"); + else + DeleteBackupFile("SYSCONF"); +} + /// Copy a directory from host_source_path (on the host FS) to nand_target_path on the NAND. /// /// Both paths should not have trailing slashes. To specify the NAND root, use "". diff --git a/Source/Core/Core/WiiRoot.h b/Source/Core/Core/WiiRoot.h index c62aaa103f..7b069d0c07 100644 --- a/Source/Core/Core/WiiRoot.h +++ b/Source/Core/Core/WiiRoot.h @@ -6,9 +6,18 @@ namespace Core { +enum class RestoreReason +{ + EmulationEnd, + CrashRecovery, +}; + void InitializeWiiRoot(bool use_temporary); void ShutdownWiiRoot(); +void BackupWiiSettings(); +void RestoreWiiSettings(RestoreReason reason); + // Initialize or clean up the filesystem contents. void InitializeWiiFileSystemContents(); void CleanUpWiiFileSystemContents(); diff --git a/Source/Core/DolphinQt/Settings/InterfacePane.cpp b/Source/Core/DolphinQt/Settings/InterfacePane.cpp index 0de6099cea..8281ae0132 100644 --- a/Source/Core/DolphinQt/Settings/InterfacePane.cpp +++ b/Source/Core/DolphinQt/Settings/InterfacePane.cpp @@ -119,12 +119,9 @@ void InterfacePane::CreateUI() // List avalable themes auto theme_search_results = Common::DoFileSearch({File::GetUserPath(D_THEMES_IDX), File::GetSysDirectory() + THEMES_DIR}); - for (const std::string& filename : theme_search_results) + for (const std::string& path : theme_search_results) { - std::string name, ext; - SplitPath(filename, nullptr, &name, &ext); - name += ext; - QString qt_name = QString::fromStdString(name); + const QString qt_name = QString::fromStdString(PathToFileName(path)); m_combobox_theme->addItem(qt_name); } @@ -137,12 +134,12 @@ void InterfacePane::CreateUI() m_combobox_userstyle->addItem(tr("(None)"), QString{}); - for (const std::string& filename : userstyle_search_results) + for (const std::string& path : userstyle_search_results) { - std::string name, ext; - SplitPath(filename, nullptr, &name, &ext); - QString qt_name = QString::fromStdString(name); - m_combobox_userstyle->addItem(qt_name, QString::fromStdString(filename)); + std::string name; + SplitPath(path, nullptr, &name, nullptr); + const QString qt_name = QString::fromStdString(name); + m_combobox_userstyle->addItem(qt_name, QString::fromStdString(path)); } // Checkboxes diff --git a/Source/Core/UICommon/GameFile.cpp b/Source/Core/UICommon/GameFile.cpp index 8499d270f4..cc64d9d3e9 100644 --- a/Source/Core/UICommon/GameFile.cpp +++ b/Source/Core/UICommon/GameFile.cpp @@ -97,11 +97,9 @@ GameFile::GameFile() = default; GameFile::GameFile(std::string path) : m_file_path(std::move(path)) { - { - std::string name, extension; - SplitPath(m_file_path, nullptr, &name, &extension); - m_file_name = name + extension; + m_file_name = PathToFileName(m_file_path); + { std::unique_ptr volume(DiscIO::CreateVolume(m_file_path)); if (volume != nullptr) { diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 76ff64ac25..5af9192711 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -31,6 +31,7 @@ #include "Core/HW/Wiimote.h" #include "Core/IOS/IOS.h" #include "Core/IOS/STM/STM.h" +#include "Core/WiiRoot.h" #include "InputCommon/GCAdapter.h" @@ -88,6 +89,8 @@ static void InitCustomPaths() void Init() { + Core::RestoreWiiSettings(Core::RestoreReason::CrashRecovery); + Config::Init(); Config::AddConfigChangedCallback(InitCustomPaths); Config::AddLayer(ConfigLoaders::GenerateBaseConfigLoader());