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 --- libs/lootcli/src/main.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 libs/lootcli/src/main.cpp (limited to 'libs/lootcli/src/main.cpp') diff --git a/libs/lootcli/src/main.cpp b/libs/lootcli/src/main.cpp new file mode 100644 index 0000000..d06e0ef --- /dev/null +++ b/libs/lootcli/src/main.cpp @@ -0,0 +1,102 @@ +#include "lootthread.h" +#include + +using namespace std; + +template +T getParameter(const std::vector& arguments, const std::string& key) +{ + auto iter = std::find(arguments.begin(), arguments.end(), std::string("--") + key); + if ((iter != arguments.end()) && ((iter + 1) != arguments.end())) { + return boost::lexical_cast(*(iter + 1)); + } else { + throw std::runtime_error(std::string("argument missing " + key)); + } +} + +template <> +bool getParameter(const std::vector& arguments, + const std::string& key) +{ + auto iter = std::find(arguments.begin(), arguments.end(), std::string("--") + key); + if (iter != arguments.end()) { + return true; + } else { + return false; + } +} + +template +T getOptionalParameter(const std::vector& arguments, + const std::string& key, T def) +{ + try { + return getParameter(arguments, key); + } catch (std::runtime_error&) { + return def; + } +} + +loot::LogLevel getLogLevel(const std::vector& arguments) +{ + const auto s = getOptionalParameter(arguments, "logLevel", ""); + const auto level = lootcli::logLevelFromString(s); + + return lootcli::toLootLogLevel(level); +} + +#ifdef _WIN32 +int wWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) +{ + _setmode(_fileno(stdout), _O_BINARY); + setlocale(LC_ALL, "en.UTF-8"); + + std::vector arguments; + int argc; + LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); + + if (argv) { + for (int i = 0; i < argc; ++i) { + size_t num_converted; + std::vector arg(wcslen(argv[i]) * sizeof(wchar_t) + 1); + + wcstombs_s(&num_converted, &(arg[0]), arg.size(), argv[i], arg.size() - 1); + + arguments.push_back(&(arg[0])); + } + } +#else +int main(int argc, char* argv[]) +{ + setlocale(LC_ALL, "en_US.UTF-8"); + + std::vector arguments; + for (int i = 0; i < argc; ++i) { + arguments.push_back(argv[i]); + } +#endif + + // design rationale: this was designed to have the actual loot stuff run in a separate + // thread. That turned out to be unnecessary atm. + + try { + lootcli::LOOTWorker worker; + + worker.setUpdateMasterlist(!getParameter(arguments, "skipUpdateMasterlist")); + worker.setGame(getParameter(arguments, "game")); + worker.setGamePath(getParameter(arguments, "gamePath")); + worker.setPluginListPath(getParameter(arguments, "pluginListPath")); + worker.setOutput(getParameter(arguments, "out")); + worker.setLogLevel(getLogLevel(arguments)); + + const auto lang = getOptionalParameter(arguments, "language", ""); + if (!lang.empty()) { + worker.setLanguageCode(lang); + } + + return worker.run(); + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what(); + return 1; + } +} -- cgit v1.3.1