From 3a006e54733dd4411a7acdaf09e63a9d1aa81e2a Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 12 Sep 2023 14:58:13 -0500 Subject: [PATCH] Fix archive parsing and BSA invalidation --- src/createinstancedialog.cpp | 18 ++++--- src/createinstancedialog.h | 10 ++++ src/createinstancedialog.ui | 90 +++++++++++++++++++++++++++++-- src/createinstancedialogpages.cpp | 35 ++++++++++++ src/createinstancedialogpages.h | 24 +++++++++ src/profile.cpp | 51 +++++++++++++----- src/settings.cpp | 30 +++++++++++ src/settings.h | 15 ++++++ src/settingsdialog.ui | 44 ++++++++++++--- src/settingsdialoggeneral.cpp | 10 ++++ 10 files changed, 298 insertions(+), 29 deletions(-) diff --git a/src/createinstancedialog.cpp b/src/createinstancedialog.cpp index c5f51e0ec..d50a2063c 100644 --- a/src/createinstancedialog.cpp +++ b/src/createinstancedialog.cpp @@ -110,6 +110,7 @@ CreateInstanceDialog::CreateInstanceDialog(const PluginContainer& pc, Settings* m_pages.push_back(std::make_unique(*this)); m_pages.push_back(std::make_unique(*this)); m_pages.push_back(std::make_unique(*this)); + m_pages.push_back(std::make_unique(*this)); m_pages.push_back(std::make_unique(*this)); m_pages.push_back(std::make_unique(*this)); m_pages.push_back(std::make_unique(*this)); @@ -355,6 +356,10 @@ void CreateInstanceDialog::finish() s.paths().setOverwrite(ci.paths.overwrite); } + s.setProfileLocalInis(ci.profileSettings.localInis); + s.setProfileLocalSaves(ci.profileSettings.localSaves); + s.setProfileArchiveInvalidation(ci.profileSettings.archiveInvalidation); + logCreation(tr("Writing %1...").arg(ci.iniPath)); // writing ini @@ -475,12 +480,13 @@ CreateInstanceDialog::CreationInfo CreateInstanceDialog::rawCreationInfo() const CreationInfo ci; - ci.type = getSelected(&cid::Page::selectedInstanceType); - ci.game = getSelected(&cid::Page::selectedGame); - ci.gameLocation = getSelected(&cid::Page::selectedGameLocation); - ci.gameVariant = getSelected(&cid::Page::selectedGameVariant, ci.game); - ci.instanceName = getSelected(&cid::Page::selectedInstanceName); - ci.paths = getSelected(&cid::Page::selectedPaths); + ci.type = getSelected(&cid::Page::selectedInstanceType); + ci.game = getSelected(&cid::Page::selectedGame); + ci.gameLocation = getSelected(&cid::Page::selectedGameLocation); + ci.gameVariant = getSelected(&cid::Page::selectedGameVariant, ci.game); + ci.instanceName = getSelected(&cid::Page::selectedInstanceName); + ci.profileSettings = getSelected(&cid::Page::profileSettings); + ci.paths = getSelected(&cid::Page::selectedPaths); if (ci.type == Portable) { ci.dataPath = QDir(InstanceManager::singleton().portablePath()).absolutePath(); diff --git a/src/createinstancedialog.h b/src/createinstancedialog.h index fe3c5646f..4495cc78e 100644 --- a/src/createinstancedialog.h +++ b/src/createinstancedialog.h @@ -66,6 +66,15 @@ class CreateInstanceDialog : public QDialog auto operator<=>(const Paths&) const = default; }; + struct ProfileSettings + { + bool localInis; + bool localSaves; + bool archiveInvalidation; + + auto operator<=>(const ProfileSettings&) const = default; + }; + // all the info filled in the various pages // struct CreationInfo @@ -78,6 +87,7 @@ class CreateInstanceDialog : public QDialog QString dataPath; QString iniPath; Paths paths; + ProfileSettings profileSettings; }; CreateInstanceDialog(const PluginContainer& pc, Settings* s, diff --git a/src/createinstancedialog.ui b/src/createinstancedialog.ui index 5c791affb..b47507559 100644 --- a/src/createinstancedialog.ui +++ b/src/createinstancedialog.ui @@ -34,7 +34,6 @@ 14 - 75 true @@ -294,7 +293,7 @@ 0 0 455 - 286 + 275 @@ -430,7 +429,7 @@ 0 0 455 - 278 + 265 @@ -546,6 +545,90 @@ + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + <h3>Configure your profile settings.</h3> + + + true + + + + + + + + + + + + + + + + Use profile-specific game INI files + + + + + + + + + + Use profile-specific save games + + + + + + + + + + Automatic archive invalidation + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + @@ -1242,7 +1325,6 @@ showAllGames gamesFilter scrollArea_2 - instanceName location browseLocation advancedPathOptions diff --git a/src/createinstancedialogpages.cpp b/src/createinstancedialogpages.cpp index c8cec45f2..1a5b24705 100644 --- a/src/createinstancedialogpages.cpp +++ b/src/createinstancedialogpages.cpp @@ -143,6 +143,12 @@ CreateInstanceDialog::Paths Page::selectedPaths() const return {}; } +CreateInstanceDialog::ProfileSettings Page::profileSettings() const +{ + // no-op + return {}; +} + IntroPage::IntroPage(CreateInstanceDialog& dlg) : Page(dlg), m_skip(GlobalSettings::hideCreateInstanceIntro()) { @@ -931,6 +937,24 @@ bool NamePage::checkName(QString parentDir, QString name) return okay; } +ProfilePage::ProfilePage(CreateInstanceDialog& dlg) + : Page(dlg) +{} + +bool ProfilePage::ready() const +{ + return true; +} + +CreateInstanceDialog::ProfileSettings ProfilePage::profileSettings() const +{ + CreateInstanceDialog::ProfileSettings profileSettings; + profileSettings.localInis = ui->profileInisCheckbox->isChecked(); + profileSettings.localSaves = ui->profileSavesCheckbox->isChecked(); + profileSettings.archiveInvalidation = ui->archiveInvalidationCheckbox->isChecked(); + return profileSettings; +} + PathsPage::PathsPage(CreateInstanceDialog& dlg) : Page(dlg), m_lastType(CreateInstanceDialog::NoType), m_label(ui->pathsLabel), m_simpleExists(ui->locationExists), m_simpleInvalid(ui->locationInvalid), @@ -1215,6 +1239,17 @@ QString ConfirmationPage::makeReview() const lines.push_back(QObject::tr("Instance name: %1").arg(ci.instanceName)); } + lines.push_back(QObject::tr("Profile settings:")); + lines.push_back( + QObject::tr(" Local INIs: %1") + .arg(ci.profileSettings.localInis ? QObject::tr("yes") : QObject::tr("no"))); + lines.push_back( + QObject::tr(" Local Saves: %1") + .arg(ci.profileSettings.localSaves ? QObject::tr("yes") : QObject::tr("no"))); + lines.push_back(QObject::tr(" Automatic Archive Invalidation: %1") + .arg(ci.profileSettings.archiveInvalidation ? QObject::tr("yes") + : QObject::tr("no"))); + if (ci.paths.downloads.isEmpty()) { // simple settings if (ci.paths.base != ci.dataPath) { diff --git a/src/createinstancedialogpages.h b/src/createinstancedialogpages.h index d9751a526..25945a2a3 100644 --- a/src/createinstancedialogpages.h +++ b/src/createinstancedialogpages.h @@ -110,6 +110,10 @@ class Page // virtual CreateInstanceDialog::Paths selectedPaths() const; + // returns the profile settings + // + virtual CreateInstanceDialog::ProfileSettings profileSettings() const; + protected: Ui::CreateInstanceDialog* ui; CreateInstanceDialog& m_dlg; @@ -557,6 +561,26 @@ class PathsPage : public Page void setIfEmpty(QLineEdit* e, const QString& path, bool force); }; + +// default settings for profiles page; allow the user to set their preferred +// defaults for the profile options +// +class ProfilePage : public Page +{ +public: + ProfilePage(CreateInstanceDialog& dlg); + + // always returns true, options are boolean + // + bool ready() const override; + + CreateInstanceDialog::ProfileSettings profileSettings() const override; + +protected: + +}; + + // nexus connection page; this reuses the ui found in the settings dialog and // is skipped if there's already an api key in the credentials manager // diff --git a/src/profile.cpp b/src/profile.cpp index c5ea5eec8..13ce41c7e 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -157,22 +157,37 @@ void Profile::findProfileSettings() { if (setting("", "LocalSaves") == QVariant()) { if (m_Directory.exists("saves")) { - storeSetting("", "LocalSaves", true); + if (!Settings::instance().profileLocalSaves()) { + m_Directory.rename("saves", "_saves"); + storeSetting("", "LocalSaves", false); + } else { + storeSetting("", "LocalSaves", true); + } } else { if (m_Directory.exists("_saves")) { - m_Directory.rename("_saves", "saves"); + if (Settings::instance().profileLocalSaves()) { + m_Directory.rename("_saves", "saves"); + storeSetting("", "LocalSaves", true); + } else { + storeSetting("", "LocalSaves", false); + } + } else { + storeSetting("", "LocalSaves", Settings::instance().profileLocalSaves()); } - storeSetting("", "LocalSaves", false); } } - if (setting("", "LocalSettings") == QVariant()) { + if (setting("", "LocalSettings") == + QVariant()) { QString backupFile = getIniFileName() + "_"; if (m_Directory.exists(backupFile)) { - storeSetting("", "LocalSettings", false); + storeSetting("", "LocalSettings", true); m_Directory.rename(backupFile, getIniFileName()); - } else { + } else if (Settings::instance().profileLocalInis()) { storeSetting("", "LocalSettings", true); + enableLocalSettings(true); + } else { + storeSetting("", "LocalSettings", false); } } @@ -183,14 +198,23 @@ void Profile::findProfileSettings() if ((invalidation != nullptr) && (dataArchives != nullptr)) { for (const QString& archive : dataArchives->archives(this)) { if (invalidation->isInvalidationBSA(archive)) { - storeSetting("", "AutomaticArchiveInvalidation", true); found = true; break; } } } - if (!found) { - storeSetting("", "AutomaticArchiveInvalidation", false); + if (found) { + if (!Settings::instance().profileArchiveInvalidation()) { + deactivateInvalidation(); + } else { + storeSetting("", "AutomaticArchiveInvalidation", true); + } + } else { + if (Settings::instance().profileArchiveInvalidation()) { + activateInvalidation(); + } else { + storeSetting("", "AutomaticArchiveInvalidation", false); + } } } } @@ -795,7 +819,9 @@ bool Profile::invalidationActive(bool* supported) const *supported = ((invalidation != nullptr) && (dataArchives != nullptr)); } - return setting("", "AutomaticArchiveInvalidation", false).toBool(); + return setting("", "AutomaticArchiveInvalidation", + Settings::instance().profileArchiveInvalidation()) + .toBool(); } void Profile::deactivateInvalidation() @@ -822,7 +848,7 @@ void Profile::activateInvalidation() bool Profile::localSavesEnabled() const { - return setting("", "LocalSaves", false).toBool(); + return setting("", "LocalSaves", Settings::instance().profileLocalSaves()).toBool(); } bool Profile::enableLocalSaves(bool enable) @@ -856,7 +882,8 @@ bool Profile::enableLocalSaves(bool enable) bool Profile::localSettingsEnabled() const { - bool enabled = setting("", "LocalSettings", false).toBool(); + bool enabled = + setting("", "LocalSettings", Settings::instance().profileLocalInis()).toBool(); if (enabled) { QStringList missingFiles; for (QString file : m_GamePlugin->iniFiles()) { diff --git a/src/settings.cpp b/src/settings.cpp index fc9985f47..b568d8028 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -214,6 +214,36 @@ void Settings::setUsePrereleases(bool b) set(m_Settings, "Settings", "use_prereleases", b); } +bool Settings::profileLocalInis() const +{ + return get(m_Settings, "Settings", "profile_local_inis", true); +} + +void Settings::setProfileLocalInis(bool b) +{ + set(m_Settings, "Settings", "profile_local_inis", b); +} + +bool Settings::profileLocalSaves() const +{ + return get(m_Settings, "Settings", "profile_local_saves", false); +} + +void Settings::setProfileLocalSaves(bool b) +{ + set(m_Settings, "Settings", "profile_local_saves", b); +} + +bool Settings::profileArchiveInvalidation() const +{ + return get(m_Settings, "Settings", "profile_archive_invalidation", false); +} + +void Settings::setProfileArchiveInvalidation(bool b) +{ + set(m_Settings, "Settings", "profile_archive_invalidation", b); +} + bool Settings::useSplash() const { return get(m_Settings, "Settings", "use_splash", true); diff --git a/src/settings.h b/src/settings.h index 6a11d6620..34a8669af 100644 --- a/src/settings.h +++ b/src/settings.h @@ -810,6 +810,21 @@ class Settings : public QObject bool usePrereleases() const; void setUsePrereleases(bool b); + // whether profiles should default to local INIs + // + bool profileLocalInis() const; + void setProfileLocalInis(bool b); + + // whether profiles should default to local saves + // + bool profileLocalSaves() const; + void setProfileLocalSaves(bool b); + + // whether profiles should default to automatic archive invalidation + // + bool profileArchiveInvalidation() const; + void setProfileArchiveInvalidation(bool b); + // whether to use spascreen or not // bool useSplash() const; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index a4c9cc7ef..27949c3aa 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -23,7 +23,7 @@ General - + @@ -44,8 +44,8 @@ 0 0 - 780 - 502 + 761 + 550 @@ -204,6 +204,36 @@ + + + + Profile Defaults + + + + + + Local INIs + + + + + + + Local Saves + + + + + + + Automatic Archive Invalidation + + + + + + @@ -1022,8 +1052,8 @@ If you disable this feature, MO will only display official DLCs this way. Please 0 0 - 780 - 502 + 778 + 497 @@ -1702,8 +1732,8 @@ If you disable this feature, MO will only display official DLCs this way. Please 0 0 - 780 - 483 + 778 + 475 diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp index 95655ac86..91fe6687e 100644 --- a/src/settingsdialoggeneral.cpp +++ b/src/settingsdialoggeneral.cpp @@ -25,6 +25,11 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) ui->checkForUpdates->setChecked(settings().checkForUpdates()); ui->usePrereleaseBox->setChecked(settings().usePrereleases()); + // profile defaults + ui->localINIs->setChecked(settings().profileLocalInis()); + ui->localSaves->setChecked(settings().profileLocalSaves()); + ui->automaticArchiveInvalidation->setChecked(settings().profileArchiveInvalidation()); + // miscellaneous ui->centerDialogs->setChecked(settings().geometry().centerDialogs()); ui->changeGameConfirmation->setChecked( @@ -64,6 +69,11 @@ void GeneralSettingsTab::update() settings().setCheckForUpdates(ui->checkForUpdates->isChecked()); settings().setUsePrereleases(ui->usePrereleaseBox->isChecked()); + // profile defaults + settings().setProfileLocalInis(ui->localINIs->isChecked()); + settings().setProfileLocalSaves(ui->localSaves->isChecked()); + settings().setProfileArchiveInvalidation(ui->automaticArchiveInvalidation->isChecked()); + // miscellaneous settings().geometry().setCenterDialogs(ui->centerDialogs->isChecked()); settings().interface().setShowChangeGameConfirmation(