aboutsummaryrefslogtreecommitdiff
path: root/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
commit7ee008e150bc5bcf76082d726f719ee0fdfda982 (patch)
tree27fb39be241fdb5ac2734c574de678977d1856d0 /libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp
Fluorine Manager: full Linux port of Mod Organizer 2
Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp')
-rw-r--r--libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp133
1 files changed, 133 insertions, 0 deletions
diff --git a/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp b/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp
new file mode 100644
index 0000000..1b7144b
--- /dev/null
+++ b/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp
@@ -0,0 +1,133 @@
+#include "gamebryobsainvalidation.h"
+
+#include "dummybsa.h"
+#include "iplugingame.h"
+#include "iprofile.h"
+#include "registry.h"
+#include <imoinfo.h>
+#include <utility.h>
+
+#include <QDir>
+#include <QStringList>
+
+#include <Windows.h>
+
+GamebryoBSAInvalidation::GamebryoBSAInvalidation(MOBase::DataArchives* dataArchives,
+ const QString& iniFilename,
+ MOBase::IPluginGame const* game)
+ : m_DataArchives(dataArchives), m_IniFileName(iniFilename), m_Game(game)
+{}
+
+bool GamebryoBSAInvalidation::isInvalidationBSA(const QString& bsaName)
+{
+ static QStringList invalidation{invalidationBSAName()};
+
+ for (const QString& file : invalidation) {
+ if (file.compare(bsaName, Qt::CaseInsensitive) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void GamebryoBSAInvalidation::deactivate(MOBase::IProfile* profile)
+{
+ prepareProfile(profile);
+}
+
+void GamebryoBSAInvalidation::activate(MOBase::IProfile* profile)
+{
+ prepareProfile(profile);
+}
+
+bool GamebryoBSAInvalidation::prepareProfile(MOBase::IProfile* profile)
+{
+ bool dirty = false;
+ QString basePath = profile->localSettingsEnabled()
+ ? profile->absolutePath()
+ : m_Game->documentsDirectory().absolutePath();
+ QString iniFilePath = basePath + "/" + m_IniFileName;
+ WCHAR setting[MAX_PATH];
+
+ // write bInvalidateOlderFiles = 1, if needed
+ if (!::GetPrivateProfileStringW(L"Archive", L"bInvalidateOlderFiles", L"0", setting,
+ MAX_PATH, iniFilePath.toStdWString().c_str()) ||
+ wcstol(setting, nullptr, 10) != 1) {
+ dirty = true;
+ if (!MOBase::WriteRegistryValue(L"Archive", L"bInvalidateOlderFiles", L"1",
+ iniFilePath.toStdWString().c_str())) {
+ qWarning("failed to activate BSA invalidation in \"%s\"",
+ qUtf8Printable(m_IniFileName));
+ }
+ }
+
+ if (profile->invalidationActive(nullptr)) {
+
+ // add the dummy bsa to the archive string, if needed
+ QStringList archives = m_DataArchives->archives(profile);
+ bool bsaInstalled = false;
+ for (const QString& archive : archives) {
+ if (isInvalidationBSA(archive)) {
+ bsaInstalled = true;
+ break;
+ }
+ }
+ if (!bsaInstalled) {
+ m_DataArchives->addArchive(profile, 0, invalidationBSAName());
+ dirty = true;
+ }
+
+ // create the dummy bsa if necessary
+ QString bsaFile = m_Game->dataDirectory().absoluteFilePath(invalidationBSAName());
+ if (!QFile::exists(bsaFile)) {
+ DummyBSA bsa(bsaVersion());
+ bsa.write(bsaFile);
+ dirty = true;
+ }
+
+ // write SInvalidationFile = "", if needed
+ if (::GetPrivateProfileStringW(L"Archive", L"SInvalidationFile",
+ L"ArchiveInvalidation.txt", setting, MAX_PATH,
+ iniFilePath.toStdWString().c_str()) ||
+ wcscmp(setting, L"") != 0) {
+ dirty = true;
+ if (!MOBase::WriteRegistryValue(L"Archive", L"SInvalidationFile", L"",
+ iniFilePath.toStdWString().c_str())) {
+ qWarning("failed to activate BSA invalidation in \"%s\"",
+ qUtf8Printable(m_IniFileName));
+ }
+ }
+ } else {
+
+ // remove the dummy bsa from the archive string, if needed
+ QStringList archivesBefore = m_DataArchives->archives(profile);
+ for (const QString& archive : archivesBefore) {
+ if (isInvalidationBSA(archive)) {
+ m_DataArchives->removeArchive(profile, archive);
+ dirty = true;
+ }
+ }
+
+ // delete the dummy bsa, if needed
+ QString bsaFile = m_Game->dataDirectory().absoluteFilePath(invalidationBSAName());
+ if (QFile::exists(bsaFile)) {
+ MOBase::shellDeleteQuiet(bsaFile);
+ dirty = true;
+ }
+
+ // write SInvalidationFile = "ArchiveInvalidation.txt", if needed
+ if (!::GetPrivateProfileStringW(L"Archive", L"SInvalidationFile", L"", setting,
+ MAX_PATH, iniFilePath.toStdWString().c_str()) ||
+ wcscmp(setting, L"ArchiveInvalidation.txt") != 0) {
+ dirty = true;
+ if (!MOBase::WriteRegistryValue(L"Archive", L"SInvalidationFile",
+ L"ArchiveInvalidation.txt",
+ iniFilePath.toStdWString().c_str())) {
+ qWarning("failed to activate BSA invalidation in \"%s\"",
+ qUtf8Printable(m_IniFileName));
+ }
+ }
+ }
+
+ return dirty;
+}