diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-11 02:37:39 -0600 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-11 02:37:39 -0600 |
| commit | 7ee008e150bc5bcf76082d726f719ee0fdfda982 (patch) | |
| tree | 27fb39be241fdb5ac2734c574de678977d1856d0 /libs/game_bethesda/src/games/fallout4vr | |
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_bethesda/src/games/fallout4vr')
19 files changed, 787 insertions, 0 deletions
diff --git a/libs/game_bethesda/src/games/fallout4vr/CMakeLists.txt b/libs/game_bethesda/src/games/fallout4vr/CMakeLists.txt new file mode 100644 index 0000000..4558388 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.16) + +add_library(game_fallout4vr SHARED + fallout4vrdataarchives.cpp + fallout4vrdataarchives.h + fallout4vrgameplugins.cpp + fallout4vrgameplugins.h + fallout4vrmoddatachecker.h + fallout4vrmoddatacontent.h + fallout4vrsavegame.cpp + fallout4vrsavegame.h + fallout4vrscriptextender.cpp + fallout4vrscriptextender.h + fallout4vrunmanagedmods.cpp + fallout4vrunmanagedmods.h + gamefallout4vr.cpp + gamefallout4vr.h +) +mo2_configure_plugin(game_fallout4vr NO_SOURCES WARNINGS 4) +mo2_default_source_group() +target_link_libraries(game_fallout4vr PRIVATE game_creation) +mo2_install_plugin(game_fallout4vr) diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vr.qrc b/libs/game_bethesda/src/games/fallout4vr/fallout4vr.qrc new file mode 100644 index 0000000..75ba055 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vr.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/Fallout4VR"> + <file alias="splash">splash.png</file> + </qresource> +</RCC> diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrdataarchives.cpp b/libs/game_bethesda/src/games/fallout4vr/fallout4vrdataarchives.cpp new file mode 100644 index 0000000..58a9a09 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrdataarchives.cpp @@ -0,0 +1,49 @@ +#include "fallout4vrdataarchives.h" + +#include "iprofile.h" +#include <utility.h> + +QStringList Fallout4VRDataArchives::vanillaArchives() const +{ + return {"Fallout4 - Textures1.ba2", "Fallout4 - Textures2.ba2", + "Fallout4 - Textures3.ba2", "Fallout4 - Textures4.ba2", + "Fallout4 - Textures5.ba2", "Fallout4 - Textures6.ba2", + "Fallout4 - Textures7.ba2", "Fallout4 - Textures8.ba2", + "Fallout4 - Textures9.ba2", "Fallout4 - Meshes.ba2", + "Fallout4 - MeshesExtra.ba2", "Fallout4 - Voices.ba2", + "Fallout4 - Sounds.ba2", "Fallout4 - Interface.ba2", + "Fallout4 - Animations.ba2", "Fallout4 - Materials.ba2", + "Fallout4 - Shaders.ba2", "Fallout4 - Startup.ba2", + "Fallout4 - Misc.ba2", "Fallout4_VR - Main.ba2", + "Fallout4_VR - Shaders.ba2", "Fallout4_VR - Textures.ba2"}; +} + +QStringList Fallout4VRDataArchives::archives(const MOBase::IProfile* profile) const +{ + QStringList result; + + QString iniFile = profile->localSettingsEnabled() + ? QDir(profile->absolutePath()).absoluteFilePath("fallout4.ini") + : localGameDirectory().absoluteFilePath("fallout4.ini"); + result.append(getArchivesFromKey(iniFile, "SResourceArchiveList")); + result.append(getArchivesFromKey(iniFile, "SResourceArchiveList2")); + + return result; +} + +void Fallout4VRDataArchives::writeArchiveList(MOBase::IProfile* profile, + const QStringList& before) +{ + QString list = before.join(", "); + + QString iniFile = profile->localSettingsEnabled() + ? QDir(profile->absolutePath()).absoluteFilePath("fallout4.ini") + : localGameDirectory().absoluteFilePath("fallout4.ini"); + if (list.length() > 255) { + int splitIdx = list.lastIndexOf(",", 256); + setArchivesToKey(iniFile, "SResourceArchiveList", list.mid(0, splitIdx)); + setArchivesToKey(iniFile, "SResourceArchiveList2", list.mid(splitIdx + 2)); + } else { + setArchivesToKey(iniFile, "SResourceArchiveList", list); + } +} diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrdataarchives.h b/libs/game_bethesda/src/games/fallout4vr/fallout4vrdataarchives.h new file mode 100644 index 0000000..71d0b3d --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrdataarchives.h @@ -0,0 +1,27 @@ +#ifndef FALLOUT4VRDATAARCHIVES_H +#define FALLOUT4VRDATAARCHIVES_H + +#include "gamebryodataarchives.h" + +namespace MOBase +{ +class IProfile; +} + +#include <QDir> +#include <QStringList> + +class Fallout4VRDataArchives : public GamebryoDataArchives +{ +public: + using GamebryoDataArchives::GamebryoDataArchives; + + virtual QStringList vanillaArchives() const override; + virtual QStringList archives(const MOBase::IProfile* profile) const override; + +private: + virtual void writeArchiveList(MOBase::IProfile* profile, + const QStringList& before) override; +}; + +#endif // Fallout4VRDataArchives_H diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrgameplugins.cpp b/libs/game_bethesda/src/games/fallout4vr/fallout4vrgameplugins.cpp new file mode 100644 index 0000000..e40a3ae --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrgameplugins.cpp @@ -0,0 +1,15 @@ +#include "fallout4vrgameplugins.h" + +using namespace MOBase; + +Fallout4VRGamePlugins::Fallout4VRGamePlugins(MOBase::IOrganizer* organizer) + : CreationGamePlugins(organizer) +{} + +bool Fallout4VRGamePlugins::lightPluginsAreSupported() +{ + auto files = m_Organizer->findFiles("f4se\\plugins", {"falloutvresl.dll"}); + if (files.isEmpty()) + return false; + return true; +} diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrgameplugins.h b/libs/game_bethesda/src/games/fallout4vr/fallout4vrgameplugins.h new file mode 100644 index 0000000..741378f --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrgameplugins.h @@ -0,0 +1,19 @@ +#ifndef _FALLOUT4VRGAMEPLUGINS_H +#define _FALLOUT4VRGAMEPLUGINS_H + +#include <creationgameplugins.h> + +#include <QObject> +#include <QtGlobal> + +class Fallout4VRGamePlugins : public CreationGamePlugins +{ + +public: + Fallout4VRGamePlugins(MOBase::IOrganizer* organizer); + +protected: + virtual bool lightPluginsAreSupported() override; +}; + +#endif // _FALLOUT4VRGAMEPLUGINS_H diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrmoddatachecker.h b/libs/game_bethesda/src/games/fallout4vr/fallout4vrmoddatachecker.h new file mode 100644 index 0000000..4517910 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrmoddatachecker.h @@ -0,0 +1,30 @@ +#ifndef FALLOUT4VR_MODATACHECKER_H +#define FALLOUT4VR_MODATACHECKER_H + +#include <gamebryomoddatachecker.h> + +class Fallout4VRModDataChecker : public GamebryoModDataChecker +{ +public: + using GamebryoModDataChecker::GamebryoModDataChecker; + +protected: + virtual const FileNameSet& possibleFolderNames() const override + { + static FileNameSet result{ + "interface", "meshes", "music", "scripts", + "sound", "strings", "textures", "trees", + "video", "materials", "f4se", "distantlod", + "asi", "Tools", "MCM", "distantland", + "mits", "dllplugins", "CalienteTools", "NetScriptFramework", + "shadersfx", "aaf"}; + return result; + } + virtual const FileNameSet& possibleFileExtensions() const override + { + static FileNameSet result{"esp", "esm", "ba2", "modgroups", "ini"}; + return result; + } +}; + +#endif // FALLOUT4VR_MODATACHECKER_H diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrmoddatacontent.h b/libs/game_bethesda/src/games/fallout4vr/fallout4vrmoddatacontent.h new file mode 100644 index 0000000..4244a95 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrmoddatacontent.h @@ -0,0 +1,44 @@ +#ifndef FALLOUT4VR_MODDATACONTENT_H +#define FALLOUT4VR_MODDATACONTENT_H + +#include <gamebryomoddatacontent.h> +#include <ifiletree.h> + +class Fallout4VRModDataContent : public GamebryoModDataContent +{ +protected: + enum Fallout4Content + { + CONTENT_MATERIAL = CONTENT_NEXT_VALUE + }; + +public: + Fallout4VRModDataContent(MOBase::IGameFeatures const* gameFeatures) + : GamebryoModDataContent(gameFeatures) + { + m_Enabled[CONTENT_SKYPROC] = false; + } + + std::vector<Content> getAllContents() const override + { + auto contents = GamebryoModDataContent::getAllContents(); + contents.push_back( + Content(CONTENT_MATERIAL, "Materials", ":/MO/gui/content/material")); + return contents; + } + + std::vector<int> + getContentsFor(std::shared_ptr<const MOBase::IFileTree> fileTree) const override + { + auto contents = GamebryoModDataContent::getContentsFor(fileTree); + for (auto e : *fileTree) { + if (e->compare("materials") == 0) { + contents.push_back(CONTENT_MATERIAL); + break; // Early break if you have nothing else to check. + } + } + return contents; + } +}; + +#endif // FALLOUT4VR_MODDATACONTENT_H diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrsavegame.cpp b/libs/game_bethesda/src/games/fallout4vr/fallout4vrsavegame.cpp new file mode 100644 index 0000000..cf29aae --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrsavegame.cpp @@ -0,0 +1,108 @@ +#include "fallout4vrsavegame.h" + +#ifdef _WIN32 +#include <Windows.h> +#else +#include <QDateTime> + +using SYSTEMTIME = _SYSTEMTIME; + +static void FileTimeToSystemTime(const FILETIME* ft, SYSTEMTIME* st) +{ + const uint64_t ticks = (static_cast<uint64_t>(ft->dwHighDateTime) << 32) | + static_cast<uint64_t>(ft->dwLowDateTime); + const int64_t unixSecs = static_cast<int64_t>(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<uint16_t>(d.year()); + st->wMonth = static_cast<uint16_t>(d.month()); + st->wDayOfWeek = static_cast<uint16_t>(d.dayOfWeek() % 7); + st->wDay = static_cast<uint16_t>(d.day()); + st->wHour = static_cast<uint16_t>(t.hour()); + st->wMinute = static_cast<uint16_t>(t.minute()); + st->wSecond = static_cast<uint16_t>(t.second()); + st->wMilliseconds = static_cast<uint16_t>(remainderHns / 10000); +} +#endif + +#include "gamefallout4vr.h" + +Fallout4VRSaveGame::Fallout4VRSaveGame(QString const& fileName, + GameFallout4VR const* game) + : GamebryoSaveGame(fileName, game, true) +{ + FileWrapper file(getFilepath(), "FO4_SAVEGAME"); + + FILETIME creationTime; + fetchInformationFields(file, m_SaveNumber, m_PCName, m_PCLevel, m_PCLocation, + creationTime); + + // 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(&creationTime, &ctime); + + setCreationTime(ctime); +} + +void Fallout4VRSaveGame::fetchInformationFields( + FileWrapper& file, uint32_t& saveNumber, QString& playerName, + unsigned short& playerLevel, QString& playerLocation, FILETIME& creationTime) const +{ + file.skip<uint32_t>(); // header size + file.skip<uint32_t>(); // header version + file.read(saveNumber); + + file.read(playerName); + + uint32_t temp; + file.read(temp); + playerLevel = static_cast<unsigned short>(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<unsigned short>(); // Player gender (0 = male) + file.skip<float>(2); // experience gathered, experience required + + file.read(creationTime); +} + +std::unique_ptr<GamebryoSaveGame::DataFields> +Fallout4VRSaveGame::fetchDataFields() const +{ + FileWrapper file(getFilepath(), "FO4_SAVEGAME"); // 10bytes + + { + QString dummyName, dummyLocation; + unsigned short dummyLevel; + uint32_t dummySaveNumber; + FILETIME dummyTime; + + fetchInformationFields(file, dummySaveNumber, dummyName, dummyLevel, dummyLocation, + dummyTime); + } + + QString ignore; + std::unique_ptr<DataFields> fields = std::make_unique<DataFields>(); + + fields->Screenshot = file.readImage(384, true); + + uint8_t saveGameVersion = file.readChar(); + file.read(ignore); // game version + file.skip<uint32_t>(); // plugin info size + + fields->Plugins = file.readPlugins(); + if (saveGameVersion >= 68) { + fields->LightPlugins = file.readLightPlugins(); + } + + return fields; +} diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrsavegame.h b/libs/game_bethesda/src/games/fallout4vr/fallout4vrsavegame.h new file mode 100644 index 0000000..e39456c --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrsavegame.h @@ -0,0 +1,23 @@ +#ifndef FALLOUT4VRSAVEGAME_H +#define FALLOUT4VRSAVEGAME_H + +#include "gamebryosavegame.h" +#include "windows_compat.h" + +class GameFallout4VR; + +class Fallout4VRSaveGame : public GamebryoSaveGame +{ +public: + Fallout4VRSaveGame(QString const& fileName, GameFallout4VR const* game); + +protected: + // Fetch easy-to-access information. + void fetchInformationFields(FileWrapper& file, uint32_t& saveNumber, + QString& playerName, unsigned short& playerLevel, + QString& playerLocation, FILETIME& creationTime) const; + + std::unique_ptr<DataFields> fetchDataFields() const override; +}; + +#endif // FALLOUT4VRSAVEGAME_H diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrscriptextender.cpp b/libs/game_bethesda/src/games/fallout4vr/fallout4vrscriptextender.cpp new file mode 100644 index 0000000..6508c6a --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrscriptextender.cpp @@ -0,0 +1,18 @@ +#include "fallout4vrscriptextender.h" + +#include <QString> +#include <QStringList> + +Fallout4VRScriptExtender::Fallout4VRScriptExtender(GameGamebryo const* game) + : GamebryoScriptExtender(game) +{} + +QString Fallout4VRScriptExtender::BinaryName() const +{ + return "f4se_loader.exe"; +} + +QString Fallout4VRScriptExtender::PluginPath() const +{ + return "f4se/plugins"; +} diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrscriptextender.h b/libs/game_bethesda/src/games/fallout4vr/fallout4vrscriptextender.h new file mode 100644 index 0000000..f7f8587 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrscriptextender.h @@ -0,0 +1,17 @@ +#ifndef FALLOUT4VRSCRIPTEXTENDER_H +#define FALLOUT4VRSCRIPTEXTENDER_H + +#include "gamebryoscriptextender.h" + +class GameGamebryo; + +class Fallout4VRScriptExtender : public GamebryoScriptExtender +{ +public: + Fallout4VRScriptExtender(GameGamebryo const* game); + + virtual QString BinaryName() const override; + virtual QString PluginPath() const override; +}; + +#endif // FALLOUT4SCRIPTEXTENDER_H diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrunmanagedmods.cpp b/libs/game_bethesda/src/games/fallout4vr/fallout4vrunmanagedmods.cpp new file mode 100644 index 0000000..a217ef0 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrunmanagedmods.cpp @@ -0,0 +1,63 @@ +#include "fallout4vrunmanagedmods.h" + +Fallout4VRUnmangedMods::Fallout4VRUnmangedMods(const GameGamebryo* game) + : GamebryoUnmangedMods(game) +{} + +Fallout4VRUnmangedMods::~Fallout4VRUnmangedMods() {} + +QStringList Fallout4VRUnmangedMods::mods(bool onlyOfficial) const +{ + QStringList result; + + QStringList pluginList = game()->primaryPlugins(); + QStringList otherPlugins = game()->DLCPlugins(); + otherPlugins.append(game()->CCPlugins()); + for (QString plugin : otherPlugins) { + pluginList.removeAll(plugin); + } + QDir dataDir(game()->dataDirectory()); + for (const QString& fileName : dataDir.entryList({"*.esp", "*.esl", "*.esm"})) { + if (!pluginList.contains(fileName, Qt::CaseInsensitive)) { + if (!onlyOfficial || pluginList.contains(fileName, Qt::CaseInsensitive)) { + result.append(fileName.chopped(4)); // trims the extension off + } + } + } + + return result; +} + +QStringList Fallout4VRUnmangedMods::secondaryFiles(const QString& modName) const +{ + // file extension in FO4 is .ba2 instead of bsa + QStringList archives; + QDir dataDir = game()->dataDirectory(); + for (const QString& archiveName : dataDir.entryList({modName + "*.ba2"})) { + archives.append(dataDir.absoluteFilePath(archiveName)); + } + return archives; +} + +QString Fallout4VRUnmangedMods::displayName(const QString& modName) const +{ + // unlike in earlier games, in fallout 4 the file name doesn't correspond to + // the public name + if (modName.compare("dlcrobot", Qt::CaseInsensitive) == 0) { + return "Automatron"; + } else if (modName.compare("dlcworkshop01", Qt::CaseInsensitive) == 0) { + return "Wasteland Workshop"; + } else if (modName.compare("dlccoast", Qt::CaseInsensitive) == 0) { + return "Far Harbor"; + } else if (modName.compare("dlcworkshop02", Qt::CaseInsensitive) == 0) { + return "Contraptions Workshop"; + } else if (modName.compare("dlcworkshop03", Qt::CaseInsensitive) == 0) { + return "Vault-Tec Workshop"; + } else if (modName.compare("dlcnukaworld", Qt::CaseInsensitive) == 0) { + return "Nuka-World"; + } else if (modName.compare("dlcultrahighresolution", Qt::CaseInsensitive) == 0) { + return "Ultra High Resolution Texture Pack"; + } else { + return modName; + } +} diff --git a/libs/game_bethesda/src/games/fallout4vr/fallout4vrunmanagedmods.h b/libs/game_bethesda/src/games/fallout4vr/fallout4vrunmanagedmods.h new file mode 100644 index 0000000..f0f15fd --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/fallout4vrunmanagedmods.h @@ -0,0 +1,18 @@ +#ifndef FALLOUT4VRUNMANAGEDMODS_H +#define FALLOUT4VRUNMANAGEDMODS_H + +#include "gamebryounmanagedmods.h" +#include <gamegamebryo.h> + +class Fallout4VRUnmangedMods : public GamebryoUnmangedMods +{ +public: + Fallout4VRUnmangedMods(const GameGamebryo* game); + ~Fallout4VRUnmangedMods(); + + virtual QStringList mods(bool onlyOfficial) const override; + virtual QStringList secondaryFiles(const QString& modName) const override; + virtual QString displayName(const QString& modName) const override; +}; + +#endif // FALLOUT4UNMANAGEDMODS_H diff --git a/libs/game_bethesda/src/games/fallout4vr/game_fallout4vr_en.ts b/libs/game_bethesda/src/games/fallout4vr/game_fallout4vr_en.ts new file mode 100644 index 0000000..4044f20 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/game_fallout4vr_en.ts @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="en_US"> +<context> + <name>GameFallout4VR</name> + <message> + <location filename="gamefallout4vr.cpp" line="82"/> + <source>Fallout 4 VR Support Plugin</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="gamefallout4vr.cpp" line="92"/> + <source>Adds support for the game Fallout 4 VR. +Splash by %1</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/libs/game_bethesda/src/games/fallout4vr/gamefallout4vr.cpp b/libs/game_bethesda/src/games/fallout4vr/gamefallout4vr.cpp new file mode 100644 index 0000000..bd2448b --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/gamefallout4vr.cpp @@ -0,0 +1,251 @@ +#include "gamefallout4vr.h" + +#include "fallout4vrdataarchives.h" +#include "fallout4vrgameplugins.h" +#include "fallout4vrmoddatachecker.h" +#include "fallout4vrmoddatacontent.h" +#include "fallout4vrsavegame.h" +#include "fallout4vrunmanagedmods.h" + +#include "versioninfo.h" +#include <executableinfo.h> +#include <gamebryolocalsavegames.h> +#include <gamebryosavegameinfo.h> +#include <pluginsetting.h> + +#include <QCoreApplication> +#include <QDir> +#include <QFileInfo> +#include <QList> +#include <QObject> +#include <QString> +#include <QStringList> + +#include <memory> + +#include "scopeguard.h" + +using namespace MOBase; + +GameFallout4VR::GameFallout4VR() {} + +bool GameFallout4VR::init(IOrganizer* moInfo) +{ + if (!GameGamebryo::init(moInfo)) { + return false; + } + + registerFeature(std::make_shared<Fallout4VRDataArchives>(this)); + registerFeature(std::make_shared<GamebryoLocalSavegames>(this, "fallout4custom.ini")); + registerFeature(std::make_shared<Fallout4VRModDataChecker>(this)); + registerFeature( + std::make_shared<Fallout4VRModDataContent>(m_Organizer->gameFeatures())); + registerFeature(std::make_shared<GamebryoSaveGameInfo>(this)); + registerFeature(std::make_shared<Fallout4VRGamePlugins>(moInfo)); + registerFeature(std::make_shared<Fallout4VRUnmangedMods>(this)); + + return true; +} + +QString GameFallout4VR::gameName() const +{ + return "Fallout 4 VR"; +} + +void GameFallout4VR::detectGame() +{ + m_GamePath = identifyGamePath(); + m_MyGamesPath = determineMyGamesPath("Fallout4VR"); +} + +QList<ExecutableInfo> GameFallout4VR::executables() const +{ + return QList<ExecutableInfo>() + << ExecutableInfo("Fallout 4 VR", findInGameFolder(binaryName())) + << ExecutableInfo("Creation Kit", findInGameFolder("CreationKit.exe")) + << ExecutableInfo("LOOT", QFileInfo(getLootPath())) + .withArgument("--game=\"Fallout4VR\""); +} + +QList<ExecutableForcedLoadSetting> GameFallout4VR::executableForcedLoads() const +{ + return QList<ExecutableForcedLoadSetting>(); +} + +QString GameFallout4VR::name() const +{ + return "Fallout 4 VR Support Plugin"; +} + +QString GameFallout4VR::localizedName() const +{ + return tr("Fallout 4 VR Support Plugin"); +} + +QString GameFallout4VR::author() const +{ + return "MO2 Contibutors"; +} + +QString GameFallout4VR::description() const +{ + return tr("Adds support for the game Fallout 4 VR.\n" + "Splash by %1") + .arg("nekoyoubi"); +} + +MOBase::VersionInfo GameFallout4VR::version() const +{ + return VersionInfo(1, 6, 1, VersionInfo::RELEASE_FINAL); +} + +QList<PluginSetting> GameFallout4VR::settings() const +{ + return QList<PluginSetting>(); +} + +void GameFallout4VR::initializeProfile(const QDir& path, ProfileSettings settings) const +{ + if (settings.testFlag(IPluginGame::MODS)) { + copyToProfile(localAppFolder() + "/Fallout4VR", path, "plugins.txt"); + } + + if (settings.testFlag(IPluginGame::CONFIGURATION)) { + if (settings.testFlag(IPluginGame::PREFER_DEFAULTS) || + !QFileInfo(myGamesPath() + "/fallout4.ini").exists()) { + copyToProfile(gameDirectory().absolutePath(), path, "fallout4.ini"); + } else { + copyToProfile(myGamesPath(), path, "fallout4.ini"); + } + + copyToProfile(myGamesPath(), path, "fallout4prefs.ini"); + copyToProfile(myGamesPath(), path, "fallout4custom.ini"); + } +} + +QString GameFallout4VR::savegameExtension() const +{ + return "fos"; +} + +QString GameFallout4VR::savegameSEExtension() const +{ + return "f4se"; +} + +std::shared_ptr<const GamebryoSaveGame> +GameFallout4VR::makeSaveGame(QString filePath) const +{ + return std::make_shared<const Fallout4VRSaveGame>(filePath, this); +} + +QString GameFallout4VR::steamAPPId() const +{ + return "611660"; +} + +QStringList GameFallout4VR::primaryPlugins() const +{ + QStringList plugins = {"fallout4.esm", "fallout4_vr.esm"}; + + plugins.append(CCPlugins()); + + return plugins; +} + +QStringList GameFallout4VR::gameVariants() const +{ + return {"Regular"}; +} + +QString GameFallout4VR::gameShortName() const +{ + return "Fallout4VR"; +} + +QStringList GameFallout4VR::validShortNames() const +{ + return {"Fallout4"}; +} + +QString GameFallout4VR::gameNexusName() const +{ + return QString(); +} + +QStringList GameFallout4VR::iniFiles() const +{ + return {"fallout4.ini", "fallout4custom.ini", "fallout4prefs.ini"}; +} + +QStringList GameFallout4VR::DLCPlugins() const +{ + return {"dlcrobot.esm", + "dlcworkshop01.esm", + "dlccoast.esm", + "dlcworkshop02.esm", + "dlcworkshop03.esm", + "dlcnukaworld.esm", + "dlcultrahighresolution.esm"}; +} + +QStringList GameFallout4VR::CCPlugins() const +{ + QStringList plugins = {}; + QFile file(gameDirectory().absoluteFilePath("Fallout4.ccc")); + if (file.open(QIODevice::ReadOnly)) { + ON_BLOCK_EXIT([&file]() { + file.close(); + }); + + if (file.size() == 0) { + return plugins; + } + while (!file.atEnd()) { + QByteArray line = file.readLine().trimmed(); + QString modName; + if ((line.size() > 0) && (line.at(0) != '#')) { + modName = QString::fromUtf8(line.constData()).toLower(); + } + + if (modName.size() > 0) { + if (!plugins.contains(modName, Qt::CaseInsensitive)) { + plugins.append(modName); + } + } + } + } + return plugins; +} + +IPluginGame::LoadOrderMechanism GameFallout4VR::loadOrderMechanism() const +{ + return IPluginGame::LoadOrderMechanism::PluginsTxt; +} + +int GameFallout4VR::nexusModOrganizerID() const +{ + return 0; //... +} + +int GameFallout4VR::nexusGameID() const +{ + return 0; +} + +QString GameFallout4VR::getLauncherName() const +{ + return binaryName(); // Fallout 4 VR has no Launcher, so we just return the name of + // the game binary +} + +QString GameFallout4VR::identifyGamePath() const +{ +#ifdef _WIN32 + QString path = "Software\\Bethesda Softworks\\" + gameName(); + return findInRegistry(HKEY_LOCAL_MACHINE, path.toStdWString().c_str(), + L"Installed Path"); +#else + return GameGamebryo::identifyGamePath(); +#endif +} diff --git a/libs/game_bethesda/src/games/fallout4vr/gamefallout4vr.h b/libs/game_bethesda/src/games/fallout4vr/gamefallout4vr.h new file mode 100644 index 0000000..acd90d1 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/gamefallout4vr.h @@ -0,0 +1,59 @@ +#ifndef GAMEFALLOUT4VR_H +#define GAMEFALLOUT4VR_H + +#include "gamegamebryo.h" + +#include <QObject> +#include <QtGlobal> + +class GameFallout4VR : public GameGamebryo +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "org.tannin.GameFallout4VR" FILE "gamefallout4vr.json") + +public: + GameFallout4VR(); + + virtual bool init(MOBase::IOrganizer* moInfo) override; + +public: // IPluginGame interface + virtual QString gameName() const override; + virtual void detectGame() override; + virtual QList<MOBase::ExecutableInfo> executables() const override; + virtual QList<MOBase::ExecutableForcedLoadSetting> + executableForcedLoads() const override; + virtual void initializeProfile(const QDir& path, + ProfileSettings settings) const override; + virtual QString steamAPPId() const override; + virtual QStringList primaryPlugins() const override; + virtual QStringList gameVariants() const override; + virtual QString gameShortName() const override; + virtual QStringList primarySources() const override { return validShortNames(); }; + virtual QStringList validShortNames() const override; + virtual QString gameNexusName() const override; + virtual QStringList iniFiles() const override; + virtual QStringList DLCPlugins() const override; + virtual QStringList CCPlugins() const override; + virtual LoadOrderMechanism loadOrderMechanism() const override; + virtual int nexusModOrganizerID() const override; + virtual int nexusGameID() const override; + virtual QString getLauncherName() const override; + +public: // IPlugin interface + virtual QString name() const override; + virtual QString localizedName() const override; + virtual QString author() const override; + virtual QString description() const override; + virtual MOBase::VersionInfo version() const override; + virtual QList<MOBase::PluginSetting> settings() const override; + +protected: + std::shared_ptr<const GamebryoSaveGame> makeSaveGame(QString filePath) const override; + QString savegameExtension() const override; + QString savegameSEExtension() const override; + + virtual QString identifyGamePath() const override; +}; + +#endif // GAMEFallout4VR_H diff --git a/libs/game_bethesda/src/games/fallout4vr/gamefallout4vr.json b/libs/game_bethesda/src/games/fallout4vr/gamefallout4vr.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/gamefallout4vr.json @@ -0,0 +1 @@ +{} diff --git a/libs/game_bethesda/src/games/fallout4vr/splash.png b/libs/game_bethesda/src/games/fallout4vr/splash.png Binary files differnew file mode 100644 index 0000000..b5908bc --- /dev/null +++ b/libs/game_bethesda/src/games/fallout4vr/splash.png |
