From 7ee008e150bc5bcf76082d726f719ee0fdfda982 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Wed, 11 Feb 2026 02:37:39 -0600 Subject: 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 --- .../src/games/fallout76/fallout76savegame.cpp | 106 +++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 libs/game_bethesda/src/games/fallout76/fallout76savegame.cpp (limited to 'libs/game_bethesda/src/games/fallout76/fallout76savegame.cpp') diff --git a/libs/game_bethesda/src/games/fallout76/fallout76savegame.cpp b/libs/game_bethesda/src/games/fallout76/fallout76savegame.cpp new file mode 100644 index 0000000..66e8a00 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout76/fallout76savegame.cpp @@ -0,0 +1,106 @@ +#include "fallout76savegame.h" + +#ifdef _WIN32 +#include +#else +#include + +using SYSTEMTIME = _SYSTEMTIME; + +static void FileTimeToSystemTime(const FILETIME* ft, SYSTEMTIME* st) +{ + const uint64_t ticks = (static_cast(ft->dwHighDateTime) << 32) | + static_cast(ft->dwLowDateTime); + const int64_t unixSecs = static_cast(ticks / 10000000ULL) - 11644473600LL; + const uint64_t remainderHns = ticks % 10000000ULL; + + const QDateTime dt = QDateTime::fromSecsSinceEpoch(unixSecs, Qt::UTC); + const QDate d = dt.date(); + const QTime t = dt.time(); + + st->wYear = static_cast(d.year()); + st->wMonth = static_cast(d.month()); + st->wDayOfWeek = static_cast(d.dayOfWeek() % 7); + st->wDay = static_cast(d.day()); + st->wHour = static_cast(t.hour()); + st->wMinute = static_cast(t.minute()); + st->wSecond = static_cast(t.second()); + st->wMilliseconds = static_cast(remainderHns / 10000); +} +#endif + +#include "gamefallout76.h" + +Fallout76SaveGame::Fallout76SaveGame(QString const& fileName, GameFallout76 const* game) + : GamebryoSaveGame(fileName, game, true) +{ + FileWrapper file(fileName, "FO76_SAVEGAME"); + + FILETIME ftime; + fetchInformationFields(file, m_PCName, m_PCLevel, m_PCLocation, m_SaveNumber, ftime); + + // A file time is a 64-bit value that represents the number of 100-nanosecond + // intervals that have elapsed since 12:00 A.M. January 1, 1601 Coordinated Universal + // Time (UTC). So we need to convert that to something useful + SYSTEMTIME ctime; + ::FileTimeToSystemTime(&ftime, &ctime); + + setCreationTime(ctime); +} + +void Fallout76SaveGame::fetchInformationFields(FileWrapper& file, QString playerName, + unsigned short playerLevel, + QString playerLocation, + unsigned long saveNumber, + FILETIME& creationTime) const +{ + + file.skip(); // header size + file.skip(); // header version + file.read(saveNumber); + + file.read(playerName); + + unsigned long temp; + file.read(temp); + playerLevel = static_cast(temp); + file.read(playerLocation); + + QString ignore; + file.read(ignore); // playtime as ascii hh.mm.ss + file.read(ignore); // race name (i.e. BretonRace) + + file.skip(); // Player gender (0 = male) + file.skip(2); // experience gathered, experience required + + FILETIME ftime; + file.read(ftime); +} + +std::unique_ptr Fallout76SaveGame::fetchDataFields() const +{ + + FileWrapper file(getFilepath(), "TESV_SAVEGAME"); // 10bytes + { + + FILETIME ftime; + fetchInformationFields(file, m_PCName, m_PCLevel, m_PCLocation, m_SaveNumber, + ftime); + } + + std::unique_ptr fields = std::make_unique(); + + file.readImage(384, true); + + uint8_t saveGameVersion = file.readChar(); + QString ignore; + file.read(ignore); // game version + file.skip(); // plugin info size + + file.readPlugins(); + if (saveGameVersion >= 68) { + file.readLightPlugins(); + } + + return fields; +} -- cgit v1.3.1