From b634eecd21bce6a6a25143e0e9a1b1b821d40133 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Mon, 16 Dec 2024 01:22:48 +1000 Subject: [PATCH] System: Allow separate configuration for multi-disc games --- src/core/fullscreen_ui.cpp | 31 +++- src/core/system.cpp | 137 +++++++++++++----- src/core/system.h | 8 +- .../controllersettingswindow.cpp | 2 +- src/duckstation-qt/gamesummarywidget.cpp | 47 +++++- src/duckstation-qt/gamesummarywidget.h | 1 + src/duckstation-qt/gamesummarywidget.ui | 28 +++- src/duckstation-qt/qthost.cpp | 8 +- src/duckstation-qt/settingswindow.cpp | 29 ++-- src/util/ini_settings_interface.cpp | 19 ++- src/util/ini_settings_interface.h | 7 +- 11 files changed, 228 insertions(+), 89 deletions(-) diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index 18daeceed..6edabffd6 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -441,6 +441,7 @@ struct ALIGN_TO_CACHE_LINE UIState // Settings SettingsPage settings_page = SettingsPage::Interface; std::unique_ptr game_settings_interface; + const GameDatabase::Entry* game_settings_db_entry; std::unique_ptr game_settings_entry; std::vector> game_list_directories_cache; GPUDevice::AdapterInfoList graphics_adapter_list_cache; @@ -870,8 +871,8 @@ void FullscreenUI::Render() if (s_state.game_settings_interface->IsEmpty()) { - if (FileSystem::FileExists(s_state.game_settings_interface->GetFileName().c_str()) && - !FileSystem::DeleteFile(s_state.game_settings_interface->GetFileName().c_str(), &error)) + if (FileSystem::FileExists(s_state.game_settings_interface->GetPath().c_str()) && + !FileSystem::DeleteFile(s_state.game_settings_interface->GetPath().c_str(), &error)) { ImGuiFullscreen::OpenInfoMessageDialog( FSUI_STR("Error"), fmt::format(FSUI_FSTR("An error occurred while deleting empty game settings:\n{}"), @@ -2724,6 +2725,7 @@ void FullscreenUI::SwitchToSettings() { s_state.game_settings_entry.reset(); s_state.game_settings_interface.reset(); + s_state.game_settings_db_entry = nullptr; s_state.game_patch_list = {}; s_state.enabled_game_patch_cache = {}; s_state.game_cheats_list = {}; @@ -2740,8 +2742,9 @@ void FullscreenUI::SwitchToSettings() void FullscreenUI::SwitchToGameSettingsForSerial(std::string_view serial) { s_state.game_settings_entry.reset(); - s_state.game_settings_interface = std::make_unique(System::GetGameSettingsPath(serial)); - s_state.game_settings_interface->Load(); + s_state.game_settings_db_entry = GameDatabase::GetEntryForSerial(serial); + s_state.game_settings_interface = + System::GetGameSettingsInterface(s_state.game_settings_db_entry, serial, true, false); PopulatePatchesAndCheatsList(serial); s_state.current_main_window = MainWindowType::Settings; s_state.settings_page = SettingsPage::Summary; @@ -2828,7 +2831,7 @@ void FullscreenUI::DoCopyGameSettings() SetSettingsChanged(s_state.game_settings_interface.get()); ShowToast("Game Settings Copied", fmt::format(FSUI_FSTR("Game settings initialized with global settings for '{}'."), - Path::GetFileTitle(s_state.game_settings_interface->GetFileName()))); + Path::GetFileTitle(s_state.game_settings_interface->GetPath()))); } void FullscreenUI::DoClearGameSettings() @@ -2837,13 +2840,13 @@ void FullscreenUI::DoClearGameSettings() return; s_state.game_settings_interface->Clear(); - if (!s_state.game_settings_interface->GetFileName().empty()) - FileSystem::DeleteFile(s_state.game_settings_interface->GetFileName().c_str()); + if (!s_state.game_settings_interface->GetPath().empty()) + FileSystem::DeleteFile(s_state.game_settings_interface->GetPath().c_str()); SetSettingsChanged(s_state.game_settings_interface.get()); ShowToast("Game Settings Cleared", fmt::format(FSUI_FSTR("Game settings have been cleared for '{}'."), - Path::GetFileTitle(s_state.game_settings_interface->GetFileName()))); + Path::GetFileTitle(s_state.game_settings_interface->GetPath()))); } void FullscreenUI::DrawSettingsWindow() @@ -3098,6 +3101,18 @@ void FullscreenUI::DrawSummarySettingsPage() MenuHeading(FSUI_CSTR("Options")); + if (s_state.game_settings_db_entry && !s_state.game_settings_db_entry->disc_set_serials.empty()) + { + // only enable for first disc + const bool is_first_disc = + (s_state.game_settings_db_entry->serial == s_state.game_settings_db_entry->disc_set_serials.front()); + DrawToggleSetting( + GetEditingSettingsInterface(), FSUI_ICONSTR(ICON_FA_COMPACT_DISC, "Use Separate Disc Settings"), + FSUI_CSTR( + "Uses separate game settings for each disc of multi-disc games. Can only be set on the first/main disc."), + "Main", "UseSeparateConfigForDiscSet", !is_first_disc, is_first_disc, false); + } + if (MenuButton(FSUI_ICONSTR(ICON_FA_COPY, "Copy Settings"), FSUI_CSTR("Copies the current global settings to this game."))) { diff --git a/src/core/system.cpp b/src/core/system.cpp index e2420d7a5..f1fea7874 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1171,20 +1171,6 @@ DiscRegion System::GetRegionForPsf(const char* path) return psf.GetRegion(); } -std::string System::GetGameSettingsPath(std::string_view game_serial) -{ - // multi-disc games => always use the first disc - const GameDatabase::Entry* entry = GameDatabase::GetEntryForSerial(game_serial); - const std::string_view serial_for_path = - (entry && !entry->disc_set_serials.empty()) ? entry->disc_set_serials.front() : game_serial; - return Path::Combine(EmuFolders::GameSettings, fmt::format("{}.ini", Path::SanitizeFileName(serial_for_path))); -} - -std::string System::GetInputProfilePath(std::string_view name) -{ - return Path::Combine(EmuFolders::InputProfiles, fmt::format("{}.ini", name)); -} - bool System::RecreateGPU(GPURenderer renderer, bool force_recreate_device, bool update_display /* = true*/) { ClearMemorySaveStates(); @@ -1487,27 +1473,108 @@ void System::ReloadInputProfile(bool display_osd_messages) ApplySettings(display_osd_messages); } -bool System::UpdateGameSettingsLayer() +std::string System::GetInputProfilePath(std::string_view name) { - std::unique_ptr new_interface; - if (g_settings.apply_game_settings && !s_state.running_game_serial.empty()) + return Path::Combine(EmuFolders::InputProfiles, fmt::format("{}.ini", name)); +} + +std::string System::GetGameSettingsPath(std::string_view game_serial, bool ignore_disc_set) +{ + // multi-disc games => always use the first disc + const GameDatabase::Entry* entry = ignore_disc_set ? nullptr : GameDatabase::GetEntryForSerial(game_serial); + const std::string_view serial_for_path = + (entry && !entry->disc_set_serials.empty()) ? entry->disc_set_serials.front() : game_serial; + return Path::Combine(EmuFolders::GameSettings, fmt::format("{}.ini", Path::SanitizeFileName(serial_for_path))); +} + +std::unique_ptr System::GetGameSettingsInterface(const GameDatabase::Entry* dbentry, + std::string_view serial, bool create, bool quiet) +{ + std::unique_ptr ret; + std::string path = GetGameSettingsPath(serial, false); + + if (FileSystem::FileExists(path.c_str())) { - std::string filename(GetGameSettingsPath(s_state.running_game_serial)); - if (FileSystem::FileExists(filename.c_str())) + if (!quiet) + INFO_COLOR_LOG(StrongCyan, "Loading game settings from '{}'...", Path::GetFileName(path)); + + Error error; + ret = std::make_unique(std::move(path)); + if (ret->Load(&error)) { - INFO_LOG("Loading game settings from '{}'...", Path::GetFileName(filename)); - new_interface = std::make_unique(std::move(filename)); - if (!new_interface->Load()) + // Check for separate disc configuration. + if (dbentry && !dbentry->disc_set_serials.empty() && dbentry->disc_set_serials.front() != serial) { - ERROR_LOG("Failed to parse game settings ini '{}'", new_interface->GetFileName()); - new_interface.reset(); + if (ret->GetBoolValue("Main", "UseSeparateConfigForDiscSet", false)) + { + if (!quiet) + { + INFO_COLOR_LOG(StrongCyan, "Using separate disc game settings serial {} for disc set {}", serial, + dbentry->disc_set_serials.front()); + } + + // Load the disc specific ini. + path = GetGameSettingsPath(serial, true); + if (FileSystem::FileExists(path.c_str())) + { + if (!ret->Load(std::move(path), &error)) + { + if (!quiet) + { + ERROR_LOG("Failed to parse separate disc game settings ini '{}': {}", Path::GetFileName(ret->GetPath()), + error.GetDescription()); + } + + if (create) + ret->Clear(); + else + ret.reset(); + } + } + else + { + if (!quiet) + INFO_COLOR_LOG(StrongCyan, "No separate disc game settings found (tried '{}')", Path::GetFileName(path)); + + ret.reset(); + + // return empty ini struct? + if (create) + ret = std::make_unique(std::move(path)); + } + } } } else { - INFO_LOG("No game settings found (tried '{}')", Path::GetFileName(filename)); + if (!quiet) + { + ERROR_LOG("Failed to parse game settings ini '{}': {}", Path::GetFileName(ret->GetPath()), + error.GetDescription()); + } + + if (!create) + ret.reset(); } } + else + { + if (!quiet) + INFO_COLOR_LOG(StrongCyan, "No game settings found (tried '{}')", Path::GetFileName(path)); + + // return empty ini struct? + if (create) + ret = std::make_unique(std::move(path)); + } + + return ret; +} + +bool System::UpdateGameSettingsLayer() +{ + std::unique_ptr new_interface; + if (g_settings.apply_game_settings && !s_state.running_game_serial.empty()) + new_interface = GetGameSettingsInterface(s_state.running_game_entry, s_state.running_game_serial, false, false); std::string input_profile_name; if (new_interface) @@ -1543,7 +1610,7 @@ void System::UpdateInputSettingsLayer(std::string input_profile_name, std::uniqu input_interface = std::make_unique(std::move(filename)); if (!input_interface->Load()) { - ERROR_LOG("Failed to parse input profile ini '{}'", Path::GetFileName(input_interface->GetFileName())); + ERROR_LOG("Failed to parse input profile ini '{}'", Path::GetFileName(input_interface->GetPath())); input_interface.reset(); input_profile_name = {}; } @@ -5543,20 +5610,12 @@ std::string System::GetGameMemoryCardPath(std::string_view serial, std::string_v std::unique_ptr ini; if (!serial.empty()) { - std::string game_settings_path = GetGameSettingsPath(serial); - if (FileSystem::FileExists(game_settings_path.c_str())) + ini = GetGameSettingsInterface(GameDatabase::GetEntryForSerial(serial), serial, false, true); + if (ini && ini->ContainsValue(section, type_key)) { - ini = std::make_unique(std::move(game_settings_path)); - if (!ini->Load()) - { - ini.reset(); - } - else if (ini->ContainsValue(section, type_key)) - { - type = Settings::ParseMemoryCardTypeName( - ini->GetTinyStringValue(section, type_key, Settings::GetMemoryCardTypeName(global_type))) - .value_or(global_type); - } + type = Settings::ParseMemoryCardTypeName( + ini->GetTinyStringValue(section, type_key, Settings::GetMemoryCardTypeName(global_type))) + .value_or(global_type); } } else if (type == MemoryCardType::PerGame) diff --git a/src/core/system.h b/src/core/system.h index 6fda00d7d..be7f612e8 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -28,6 +28,7 @@ enum class GPUVSyncMode : u8; class Controller; class GPUTexture; +class INISettingsInterface; class MediaCapture; namespace BIOS { @@ -153,7 +154,12 @@ DiscRegion GetRegionForExe(const char* path); DiscRegion GetRegionForPsf(const char* path); /// Returns the path for the game settings ini file for the specified serial. -std::string GetGameSettingsPath(std::string_view game_serial); +std::string GetGameSettingsPath(std::string_view game_serial, bool ignore_disc_set); + +/// Returns the loaded interface for the game settings ini file for the specified serial. If create is true, an empty +/// ini reader will be returned if the file does not exist. If quit is true, no log messages will be emitted. +std::unique_ptr GetGameSettingsInterface(const GameDatabase::Entry* dbentry, + std::string_view serial, bool create, bool quiet); /// Returns the path for the input profile ini file with the specified name (may not exist). std::string GetInputProfilePath(std::string_view name); diff --git a/src/duckstation-qt/controllersettingswindow.cpp b/src/duckstation-qt/controllersettingswindow.cpp index 4c76f3d87..7fc7c8a82 100644 --- a/src/duckstation-qt/controllersettingswindow.cpp +++ b/src/duckstation-qt/controllersettingswindow.cpp @@ -221,7 +221,7 @@ void ControllerSettingsWindow::onNewProfileClicked() { QMessageBox::critical( this, tr("Error"), - tr("Failed to save the new profile to '%1'.").arg(QString::fromStdString(temp_si.GetFileName()))); + tr("Failed to save the new profile to '%1'.").arg(QString::fromStdString(temp_si.GetPath()))); return; } diff --git a/src/duckstation-qt/gamesummarywidget.cpp b/src/duckstation-qt/gamesummarywidget.cpp index 8fcf6f5f7..493cc922a 100644 --- a/src/duckstation-qt/gamesummarywidget.cpp +++ b/src/duckstation-qt/gamesummarywidget.cpp @@ -86,6 +86,13 @@ GameSummaryWidget::~GameSummaryWidget() = default; void GameSummaryWidget::reloadGameSettings() { + if (m_ui.separateDiscSettings->isVisible() && m_ui.separateDiscSettings->isEnabled()) + { + m_ui.separateDiscSettings->setCheckState( + m_dialog->getBoolValue("Main", "UseSeparateConfigForDiscSet", std::nullopt).value_or(false) ? Qt::Checked : + Qt::Unchecked); + } + if (m_dialog->getBoolValue("ControllerPorts", "UseGameSettingsForController", std::nullopt).value_or(false)) { const QSignalBlocker sb(m_ui.inputProfile); @@ -214,6 +221,28 @@ void GameSummaryWidget::populateUi(const std::string& path, const std::string& s m_ui.entryType->setCurrentIndex(static_cast(gentry->type)); } + if (entry && !entry->disc_set_serials.empty()) + { + if (serial == entry->disc_set_serials.front()) + { + m_ui.separateDiscSettings->setCheckState( + m_dialog->getBoolValue("Main", "UseSeparateConfigForDiscSet", std::nullopt).value_or(false) ? Qt::Checked : + Qt::Unchecked); + connect(m_ui.separateDiscSettings, &QCheckBox::checkStateChanged, this, + &GameSummaryWidget::onSeparateDiscSettingsChanged); + } + else + { + // set disabled+checked if not first disc + m_ui.separateDiscSettings->setCheckState(Qt::Checked); + m_ui.separateDiscSettings->setEnabled(false); + } + } + else + { + m_ui.separateDiscSettings->setVisible(false); + } + m_ui.compatibilityComments->setVisible(!m_compatibility_comments.isEmpty()); m_ui.inputProfile->addItem(QIcon::fromTheme(QStringLiteral("global-line")), tr("Use Global Settings")); @@ -228,6 +257,19 @@ void GameSummaryWidget::populateUi(const std::string& path, const std::string& s updateWindowTitle(); } +void GameSummaryWidget::onSeparateDiscSettingsChanged(Qt::CheckState state) +{ + if (state == Qt::Checked) + m_dialog->setBoolSettingValue("Main", "UseSeparateConfigForDiscSet", true); + else + m_dialog->removeSettingValue("Main", "UseSeparateConfigForDiscSet"); +} + +void GameSummaryWidget::updateWindowTitle() +{ + m_dialog->setGameTitle(m_ui.title->text().toStdString()); +} + void GameSummaryWidget::populateCustomAttributes() { auto lock = GameList::GetLock(); @@ -257,11 +299,6 @@ void GameSummaryWidget::populateCustomAttributes() } } -void GameSummaryWidget::updateWindowTitle() -{ - m_dialog->setGameTitle(m_ui.title->text().toStdString()); -} - void GameSummaryWidget::setCustomTitle(const std::string& text) { m_ui.restoreTitle->setEnabled(!text.empty()); diff --git a/src/duckstation-qt/gamesummarywidget.h b/src/duckstation-qt/gamesummarywidget.h index 15718f4ca..7f1ced200 100644 --- a/src/duckstation-qt/gamesummarywidget.h +++ b/src/duckstation-qt/gamesummarywidget.h @@ -31,6 +31,7 @@ protected: void showEvent(QShowEvent* event) override; private Q_SLOTS: + void onSeparateDiscSettingsChanged(Qt::CheckState state); void onCustomLanguageChanged(int language); void onCompatibilityCommentsClicked(); void onInputProfileChanged(int index); diff --git a/src/duckstation-qt/gamesummarywidget.ui b/src/duckstation-qt/gamesummarywidget.ui index b8049a780..e84ced09d 100644 --- a/src/duckstation-qt/gamesummarywidget.ui +++ b/src/duckstation-qt/gamesummarywidget.ui @@ -208,13 +208,6 @@ - - - - false - - - @@ -344,6 +337,27 @@ + + + + + + false + + + + + + + Uses separate game settings for each disc of multi-disc games. Can only be set on the first/main disc. + + + Use Separate Disc Settings + + + + + diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index 7e2814f7d..5366486f7 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -227,14 +227,14 @@ bool QtHost::SaveGameSettings(SettingsInterface* sif, bool delete_if_empty) // if there's no keys, just toss the whole thing out if (delete_if_empty && ini->IsEmpty()) { - INFO_LOG("Removing empty gamesettings ini {}", Path::GetFileName(ini->GetFileName())); + INFO_LOG("Removing empty gamesettings ini {}", Path::GetFileName(ini->GetPath())); // grab the settings lock while we're writing the file, that way the CPU thread doesn't try // to read it at the same time. const auto lock = Host::GetSettingsLock(); - if (FileSystem::FileExists(ini->GetFileName().c_str()) && - !FileSystem::DeleteFile(ini->GetFileName().c_str(), &error)) + if (FileSystem::FileExists(ini->GetPath().c_str()) && + !FileSystem::DeleteFile(ini->GetPath().c_str(), &error)) { Host::ReportErrorAsync( TRANSLATE_SV("QtHost", "Error"), @@ -472,7 +472,7 @@ bool QtHost::InitializeConfig(std::string settings_filename) QStringLiteral( "Failed to save configuration to\n\n%1\n\nThe error was: %2\n\nPlease ensure this directory is writable. You " "can also try portable mode by creating portable.txt in the same directory you installed DuckStation into.") - .arg(QString::fromStdString(s_base_settings_interface->GetFileName())) + .arg(QString::fromStdString(s_base_settings_interface->GetPath())) .arg(QString::fromStdString(error.GetDescription()))); return false; } diff --git a/src/duckstation-qt/settingswindow.cpp b/src/duckstation-qt/settingswindow.cpp index 4d9726950..af0cae345 100644 --- a/src/duckstation-qt/settingswindow.cpp +++ b/src/duckstation-qt/settingswindow.cpp @@ -662,7 +662,10 @@ void SettingsWindow::setGameTitle(std::string title) { m_title = std::move(title); - const QString window_title = tr("%1 [%2]").arg(QString::fromStdString(m_title)).arg(QString::fromStdString(m_serial)); + const QString window_title = + tr("%1 [%2]") + .arg(QString::fromStdString(m_title)) + .arg(QtUtils::StringViewToQString(m_sif ? Path::GetFileName(m_sif->GetPath()) : std::string_view(m_serial))); setWindowTitle(window_title); } @@ -695,13 +698,13 @@ SettingsWindow* SettingsWindow::openGamePropertiesDialog(const std::string& path } std::string real_serial = dentry ? std::string(dentry->serial) : std::move(serial); - std::string ini_filename = System::GetGameSettingsPath(real_serial); + std::unique_ptr sif = System::GetGameSettingsInterface(dentry, real_serial, true, false); - // check for an existing dialog with this crc + // check for an existing dialog with this serial for (SettingsWindow* dialog : s_open_game_properties_dialogs) { if (dialog->isPerGameSettings() && - static_cast(dialog->getSettingsInterface())->GetFileName() == ini_filename) + static_cast(dialog->getSettingsInterface())->GetPath() == sif->GetPath()) { dialog->show(); dialog->raise(); @@ -713,10 +716,6 @@ SettingsWindow* SettingsWindow::openGamePropertiesDialog(const std::string& path } } - std::unique_ptr sif = std::make_unique(std::move(ini_filename)); - if (FileSystem::FileExists(sif->GetFileName().c_str())) - sif->Load(); - SettingsWindow* dialog = new SettingsWindow(path, std::move(title), std::move(real_serial), hash, region, dentry, std::move(sif)); dialog->show(); @@ -737,14 +736,14 @@ void SettingsWindow::closeGamePropertiesDialogs() bool SettingsWindow::setGameSettingsBoolForSerial(const std::string& serial, const char* section, const char* key, bool value) { - std::string ini_filename = System::GetGameSettingsPath(serial); - if (ini_filename.empty()) + if (serial.empty()) return false; - INISettingsInterface sif(std::move(ini_filename)); - if (FileSystem::FileExists(sif.GetFileName().c_str())) - sif.Load(); + std::unique_ptr sif = + System::GetGameSettingsInterface(GameDatabase::GetEntryForSerial(serial), serial, true, false); + if (!sif) + return false; - sif.SetBoolValue(section, key, value); - return sif.Save(); + sif->SetBoolValue(section, key, value); + return sif->Save(); } diff --git a/src/util/ini_settings_interface.cpp b/src/util/ini_settings_interface.cpp index 855d49ee9..ebfe98a39 100644 --- a/src/util/ini_settings_interface.cpp +++ b/src/util/ini_settings_interface.cpp @@ -19,7 +19,7 @@ LOG_CHANNEL(Settings); // we only allow one ini to be parsed at any point in time. static std::mutex s_ini_load_save_mutex; -INISettingsInterface::INISettingsInterface(std::string filename) : m_filename(std::move(filename)), m_ini(true, true) +INISettingsInterface::INISettingsInterface(std::string filename) : m_path(std::move(filename)), m_ini(true, true) { } @@ -31,7 +31,7 @@ INISettingsInterface::~INISettingsInterface() bool INISettingsInterface::Load(Error* error /* = nullptr */) { - if (m_filename.empty()) + if (m_path.empty()) { Error::SetStringView(error, "Filename is not set."); return false; @@ -39,7 +39,7 @@ bool INISettingsInterface::Load(Error* error /* = nullptr */) std::unique_lock lock(s_ini_load_save_mutex); SI_Error err = SI_FAIL; - auto fp = FileSystem::OpenManagedCFile(m_filename.c_str(), "rb", error); + auto fp = FileSystem::OpenManagedCFile(m_path.c_str(), "rb", error); if (fp) { err = m_ini.LoadFile(fp.get()); @@ -50,16 +50,23 @@ bool INISettingsInterface::Load(Error* error /* = nullptr */) return (err == SI_OK); } +bool INISettingsInterface::Load(std::string new_path, Error* error /*= nullptr*/) +{ + m_path = std::move(new_path); + m_ini.Reset(); + return Load(error); +} + bool INISettingsInterface::Save(Error* error /* = nullptr */) { - if (m_filename.empty()) + if (m_path.empty()) { Error::SetStringView(error, "Filename is not set."); return false; } std::unique_lock lock(s_ini_load_save_mutex); - FileSystem::AtomicRenamedFile fp = FileSystem::CreateAtomicRenamedFile(m_filename, error); + FileSystem::AtomicRenamedFile fp = FileSystem::CreateAtomicRenamedFile(m_path, error); SI_Error err = SI_FAIL; if (fp) { @@ -78,7 +85,7 @@ bool INISettingsInterface::Save(Error* error /* = nullptr */) if (err != SI_OK) { - WARNING_LOG("Failed to save settings to '{}'.", m_filename); + WARNING_LOG("Failed to save settings to '{}'.", m_path); return false; } diff --git a/src/util/ini_settings_interface.h b/src/util/ini_settings_interface.h index 995f32eaa..38871e2b3 100644 --- a/src/util/ini_settings_interface.h +++ b/src/util/ini_settings_interface.h @@ -13,12 +13,13 @@ class INISettingsInterface final : public SettingsInterface { public: - INISettingsInterface(std::string filename); + INISettingsInterface(std::string path); ~INISettingsInterface() override; - const std::string& GetFileName() const { return m_filename; } + const std::string& GetPath() const { return m_path; } bool Load(Error* error = nullptr); + bool Load(std::string new_path, Error* error = nullptr); bool Save(Error* error = nullptr) override; void Clear() override; @@ -61,7 +62,7 @@ public: using SettingsInterface::GetUIntValue; private: - std::string m_filename; + std::string m_path; CSimpleIniA m_ini; bool m_dirty = false; };