aboutsummaryrefslogtreecommitdiff
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
...
* Fix zenity symbol lookup errors when launching winetricksSulfurNitride2026-03-311-5/+22
| | | | | | | | | | The restoreOrig lambda only restored env vars when FLUORINE_ORIG_* was set, with no fallback. If those vars were missing, bundled library paths leaked into winetricks/zenity causing FcConfigSetDefaultSubstitute symbol errors. Now uses the same restoreOrStrip pattern as protonlauncher.cpp — strip paths containing "fluorine" as fallback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Write logs to instance directory instead of CWDSulfurNitride2026-03-291-14/+3
| | | | | | | | | Logs were being created in the current working directory (defaulting to $HOME when launched from a desktop entry). Now uses the instance directory passed to setLogDirectory() so each instance gets its own logs/ folder. Removes unused FLUORINE_LAUNCH_DIR env var. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Block game launch when no Wine prefix is configuredSulfurNitride2026-03-291-6/+20
| | | | | | | | Instead of logging a warning and attempting to launch (which fails with EACCES), show a clear error dialog directing the user to Settings → Wine/Proton to create a prefix. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Clean bundled library paths before launching winetricksSulfurNitride2026-03-281-0/+19
| | | | | | | | | | Winetricks spawns kdialog/zenity for its GUI, which inherit Fluorine's LD_LIBRARY_PATH pointing at bundled Qt .so files. On SteamOS (Steam Deck) this causes symbol lookup errors in the system kdialog. Restore the original host library paths from FLUORINE_ORIG_* env vars before launching winetricks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Hard-blacklist rootbuilder plugin from loadingSulfurNitride2026-03-281-0/+11
| | | | | | | | RootBuilder is incompatible with Fluorine/Linux. Add a permanent hard blacklist (case-insensitive) in loadPlugins() so it is silently skipped for all users. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* VFS case-insensitive inode paths, Root Builder browse, multi-select download ↵SulfurNitride2026-03-2711-5/+184
| | | | | | | | | | | | | | | | | delete, hide LOOT sort - VFS: resolve canonical (mod-provided) case for inode paths instead of Wine's requested case, preventing duplicate Overwrite entries with mismatched casing - Root Builder: fix deployRootFiles not running (m_gameDir set too late, setRootBuilderEnabled missing from prepareVFS path) - Root Builder: add "Browse Root Builder" button to Data tab, opens game root with deployed Root files visible - Mod validity: treat mods with only a Root/ folder as valid when VFS Root Builder is enabled - Downloads: multi-select delete via Delete key and context menu - Hide LOOT Sort button on Linux Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Multi-dir plugin loading, VFS Root Builder, Wine registry check, column ↵SulfurNitride2026-03-2215-634/+763
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | visibility fix Plugin loading: - Remove symlink-based ensureBundledPluginsLinked(), replace with multi-dir search (bundled dir takes priority, instance dir adds extras only) - Auto-clean stale symlinks from instance plugins/ dirs on startup - Add mergedProxyList() for proxy plugin discovery across both dirs VFS Root Builder (replaces Python rootbuilder.py): - Native C++ Root Builder integrated into FuseConnector - Deploy mod Root/ files to game dir before FUSE mount, clear on unmount - Per-instance toggle in Instance Manager (default: on) - Root Builder path normalization in processrunner.cpp: rewrite binary and start-in paths from mods/.../Root/ to Game Root for correct Wine path resolution (fixes SKSE + EngineFixes versionlib lookup) - Expose game dir and prefix to SLR pressure-vessel via --filesystem= Wine registry check: - Read/write Wine prefix system.reg (HKLM) with timestamp-aware parsing - Auto-check game install path before launch, prompt to fix if mismatched - Updates both Software\ and Wow6432Node\ registry keys Column visibility fix: - Guard updateGroupByProxy() during QHeaderView::restoreState() to prevent sort indicator restoration from triggering setSourceModel() which resets all columns to visible Python proxy: - Skip FixGameRegKey.py, crashlogtools, rootbuilder.py (Windows-only or replaced by native implementations) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Raise open file descriptor limit to 65536 in all launchersSulfurNitride2026-03-211-0/+5
| | | | | | | | Large modlists (e.g. Gate To Sovngarde) exceed the default 1024 fd limit during FUSE VFS recursive directory iteration, causing "Too many open files" errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add per-session timestamped log files in launch directory, keep last 5SulfurNitride2026-03-181-5/+29
| | | | | | | | | | Each launch creates a new mo_interface_YYYY-MM-DD_HH-MM-SS.log in a logs/ folder next to where fluorine-manager was run from. Old logs are cleaned up to keep only the 5 most recent. Launcher scripts export FLUORINE_LAUNCH_DIR before cd'ing to the bin directory so the C++ side knows the original working directory. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix Steam game mode: strip LD_PRELOAD, robust looksValid(), restore env for ↵SulfurNitride2026-03-171-0/+1
| | | | | | | | | | | | | | | | | | games Steam injects 32-bit gameoverlayrenderer.so via LD_PRELOAD which causes "wrong ELF class" errors for 64-bit Qt6 apps. Save and clear LD_PRELOAD in both launcher and AppRun scripts, restore it in ProtonLauncher for game processes. Also hardens looksValid() with QFileInfo::exists() for absolute paths (QDir::exists() has edge cases with relative subdirectory paths), adds case-insensitive directory walking fallback, and adds debug logging to both looksValid() and detectGame(). Adds ~/.steam/debian-installation to Python steam_utils.py candidates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix stale symlink check in ensureBundledPluginsLinked for /var/home distrosSulfurNitride2026-03-161-1/+7
| | | | | | | | | | | | | | | On Bazzite (and other Fedora immutable distros), /home/ is a symlink to /var/home/. This caused the symlink staleness check to always fail when desktop mode and game mode resolved $HOME differently, deleting and re-creating plugin symlinks on every game-mode launch. If re-creation failed (e.g. race or gamescope restriction), libbasic_games.so would be missing from the per-instance plugin dir, producing the "game plugin 'Oblivion Remastered' doesn't exist" (PluginGone) error. Fix: use canonicalFilePath() on both sides of the comparison so paths that differ only by symlink component (/home/ vs /var/home/) compare equal. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix game domain override for all Nexus API request types (site mods)SulfurNitride2026-03-152-11/+21
| | | | | | | | | | | | | | | | | | The previous fix only overrode m_GameName in requestFileInfo and requestDownloadURL, but after the download completes STATE_FETCHINGMODINFO triggers requestDescription with the same fallback game plugin issue, causing 404s for nexusmods.com/site mods. Consolidate into applyGameNameOverride() helper called from: - requestFileInfo - requestDownloadURL - requestDescription - requestModInfo This ensures all API calls use "site" as the game domain when no matching game plugin is found. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix const mismatch: foundGame must be const IPluginGame* to accept m_ManagedGameSulfurNitride2026-03-151-1/+1
| | | | Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix NXM handler rejecting nexusmods.com/site tool downloadsSulfurNitride2026-03-152-13/+41
| | | | | | | | | | | | | | | | | | Tools like BethINI Pie use the "site" game domain on Nexus, which has no matching game plugin. Previously this triggered the "Wrong Game" error. Now "site" (and any other domain with no plugin) is allowed: - downloadmanager: detect "site" NXM links and allow download using managed game as context; propagate raw game name ("site") through pending tracking and API requests for correct Nexus API URLs - downloadmanager: in nxmFileInfoAvailable, default info->gameName to the raw game name before plugin lookup so "site" is preserved when no matching plugin is found - nexusinterface: override m_GameName with raw game name in both requestFileInfo and requestDownloadURL when the plugin is a fallback (i.e. doesn't actually match the requested game domain) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add Steam Linux Runtime (SLR) support + fix Use Proton defaultSulfurNitride2026-03-1513-12/+300
| | | | | | | | | | | | | | | | | | | | | | Steam Linux Runtime: - New Rust module (libs/nak/src/slr.rs): download SteamLinuxRuntime_sniper from repo.steampowered.com, SHA256 verification, BUILD_ID update checks - nak_ffi exports: nak_slr_is_installed, nak_slr_get_run_script, nak_download_slr - ProtonLauncher: wraps Proton launch inside SLR pressure-vessel container when enabled (run -- proton waitforexitandrun game.exe) - Instance Manager: SLR checkbox (default on) beside Steam DRM checkbox - Main window: pre-check downloads SLR before launch if needed - Proton settings tab: "Download Steam Linux Runtime" button - spawn.cpp: reads fluorine/use_slr per-instance INI key - Logs "Final command:" showing full assembled launch command Bug fixes: - Fix Use Proton off by default for plugin executables (executableslist.cpp) - Fix Use Proton off by default for file tree right-click (filetree.cpp) - Fix Fedora 43 Qt platform plugin crash: explicit QT_QPA_PLATFORM_PLUGIN_PATH - Add Qt6::Concurrent to CMakeLists for QtConcurrent background downloads Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix false 'libfuse3 not found' warning on Debian/UbuntuSulfurNitride2026-03-141-6/+23
| | | | | | | | | On Debian/Ubuntu, libfuse3-3 (runtime) installs libfuse3.so.3 but not the unversioned libfuse3.so symlink — that requires libfuse3-dev. Add .so.3 variants to the FUSE detection check so users with only the runtime package don't get a spurious warning. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Bundle PBS Python 3.12 + PyQt6, restore Python plugins as .py filesSulfurNitride2026-03-135-417/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | - Replace portable Python approach with python-build-standalone 3.12.13 (20260310 release) bundled directly in the distribution. Python is now always available without user setup — removes the Python settings tab. - PyQt6 staged to plugins/libs/PyQt6/ with bundled Qt stripped out; patchelf'd to use our existing bundled Qt in lib/ instead of duplicating it. - Restored native-converted plugins back to .py files: Form43Checker, ScriptExtenderPluginChecker, DDSPreview, basic_games, rootbuilder, installer_omod. Removed all *_native CMake targets. - pythonrunner.cpp: removed venv/MO2_PYTHON_DIR lookup; always uses bundled Python at <exe_dir>/python, system Python as last-resort fallback. - plugincontainer.cpp: removed fluorine/python_enabled gate (Python always loads), demoted proxy loading log messages from warn to debug, silenced [plugin-diag] stderr spam. - Dockerfile: switched from uv venv to PBS install_only tarball; PBS Python used for both build-time pybind11 compilation and runtime distribution. - build-inner.sh: aggressive Python staging (strip test/tkinter/ensurepip/ distutils/lib2to3/idlelib; wipe build-time site-packages, restore psutil+vdf). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Replace wrestool with native Rust PE icon extraction (pelite)SulfurNitride2026-03-122-1/+4
| | | | | | | | | | | | | | | | | - Add icons.rs to nak crate: parses PE resource sections, extracts RT_GROUP_ICON/RT_ICON and builds ICO files in memory - Expose nak_extract_exe_icon() FFI for C++ consumption - Update iconForExecutable() to use Rust FFI instead of shelling out to wrestool; reads all ICO entries for correct color depth - Fix BasicGamePlugin::gameIcon() to call iconForExecutable() (was returning empty QIcon, causing placeholder icons for BG3/Cyberpunk) - Move app icon setup: setDesktopFileName + setWindowIcon to MOApplication constructor (fixes Wayland taskbar/decoration icon) - Move data/com.fluorine.* to data/icons/, install to XDG paths at launch for Wayland compositor icon resolution - Remove icoutils dependency from Docker image and build output Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix build: add missing Qt6 find_package for OMOD installer, fix default argSulfurNitride2026-03-121-1/+1
| | | | | | | - Add find_package(Qt6) and qt_standard_project_setup() to installer_omod_native CMakeLists - Remove duplicate default argument from fillStatForFile definition in mo2filesystem.cpp Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Replace Python plugins with native C++ .so, remove bundled Python (~95MB)SulfurNitride2026-03-129-32/+503
| | | | | | | | | | | | | | - Add native plugins: form43_checker, script_extender_checker, preview_dds, basic_games (75 game defs via IPluginProxy pattern with Steam/GOG detection) - Remove portable Python from Dockerfile and build-inner.sh - Add Python settings tab with venv support (system python3 + PyQt6) - Skip loading plugin_python.so when Python disabled (default: off) - Update pythonrunner.cpp to use venv at ~/.local/share/fluorine/python-venv/ - Preserve real file permissions in FUSE VFS (fixes native executable +x bits) - Add FUSE_SET_ATTR_MODE handler so chmod works through VFS - Fix desktop shortcut Exec= to use fluorine-manager launcher, not bare binary Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add per-executable Proton toggle and terminal launch optionSulfurNitride2026-03-129-40/+197
| | | | | | | | | | | | | New checkboxes in Edit Executables dialog: - "Use Proton": controls whether the executable launches through Proton (default on for backward compat). Disable for native Linux tools. - "Open in terminal": launches the executable in a terminal window showing stdout/stderr output, useful for debugging. Auto-detects terminal emulator (konsole, gnome-terminal, alacritty, kitty, foot, xterm). Terminal stays open after process exits showing the exit code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix rmdir for empty overwrite directory cleanupSulfurNitride2026-03-111-1/+1
| | | | | | | QDir(path).rmdir(".") doesn't work on Linux — can't rmdir("."). Use QDir().rmdir(path) to remove by absolute path instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix empty directory cleanup after overwrite moveSulfurNitride2026-03-111-3/+7
| | | | | | | | Sort directories by path length descending (deepest first) before rmdir, so leaf directories like NVSE/Plugins/Tweaks/INIs are removed before their parents. The previous prepend approach didn't guarantee depth-first order. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix "Create Mod..." and "Move content to Mod..." overwrite context menu actionsSulfurNitride2026-03-111-37/+47
| | | | | | | | | | | | The previous implementation used Windows SHFileOperation semantics that don't work on Linux: literal wildcard in paths, QFile::copy on directories, absolutePath() instead of absoluteFilePath(), and GetLastError() for errors. Rewrite moveOverwriteContentsTo() to recursively iterate all files, compute relative paths, and move each file individually with cross-filesystem fallback. Empty directories in overwrite are cleaned up after the move. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix tracked writes false positives, stale entries, portability, and launcher ↵SulfurNitride2026-03-113-9/+78
| | | | | | | | | | | | | | | | self-destruct - Remove initialScan() from mount and unmount — its heuristic ("file exists in both overwrite and a mod") caused false-positive tracking of game-generated config files. Tracking now only happens through explicit UI actions or snapshot-based detectManualMoves(). - Prune stale tracked entries on load when mod folder no longer exists on disk. - Store mod paths as relative (to JSON file parent) for instance portability; legacy absolute paths auto-migrate on next save. - Guard launcher sync against HERE==BIN_DST to prevent rm -rf self-destruct when running directly from ~/.local/share/fluorine/bin/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove FUSE passthrough, flake.nix, and stop archiving build outputSulfurNitride2026-03-118-269/+2
| | | | | | | | | | | | | FUSE passthrough caused Wine DLL loading failures (ERROR_NOACCESS 0x3E6) for all file types, not just executables. Root cause is a kernel-level incompatibility between FUSE passthrough I/O and Wine's file access patterns. Removed all passthrough code, the passthrough helper binary, libcap dependency, and the settings UI toggle. Also removed flake.nix (unused with Docker build system) and stopped tar.gz'ing the build output since GitHub zips release assets automatically. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Check CAP_SYS_ADMIN at runtime before negotiating FUSE passthroughSulfurNitride2026-03-112-1/+23
| | | | | | | | | Negotiating passthrough without the capability caused Wine/Proton DLL loading failures (SKSE plugins returning error 0x36). Now checks the process's effective capability set via libcap before telling the kernel we want passthrough. Also adds qt.conf for AT_SECURE compatibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix cap_sys_admin apply: copy-patch-replace to avoid text file busySulfurNitride2026-03-112-6/+12
| | | | | | | | patchelf can't modify a running binary. Now copies the binary to a temp file, patches RPATH and applies setcap on the copy, then replaces the original with mv. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Patch RPATH to absolute paths when applying cap_sys_adminSulfurNitride2026-03-112-10/+29
| | | | | | | | | glibc's ld.so ignores $ORIGIN in RPATH for capability binaries (AT_SECURE mode), causing "cannot open shared object" errors. Now patchelf rewrites RPATH to absolute paths before setcap runs, both in the settings dialog and the auto-apply at mount time. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix LOOT ambiguous load order: use loadorder.txt as canonical orderSulfurNitride2026-03-111-26/+23
| | | | | | | | Instead of prepending base ESMs to plugins.txt (wrong order), generate plugins.txt from loadorder.txt with active/inactive markers from the original plugins.txt. This ensures both files agree on plugin order. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix LOOT "ambiguous load order" by merging base ESMs into plugins.txtSulfurNitride2026-03-111-4/+53
| | | | | | | | | MO2's plugins.txt omits implicitly-active base game ESMs — LOOT needs every plugin listed to determine unambiguous load order. Now merges entries from loadorder.txt that are missing from plugins.txt before passing the files to LOOT. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix LOOT launch: clean QT_PLUGIN_PATH and LD_LIBRARY_PATH from envSulfurNitride2026-03-111-2/+11
| | | | | | | | LOOT's AppImage bundles its own Qt — inheriting Fluorine's QT_PLUGIN_PATH caused incompatible Qt plugin loading (exit code 6). Also clean LD_LIBRARY_PATH when the original was empty. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix FUSE passthrough: use proper API, drop LD_LIBRARY_PATH, auto-apply capSulfurNitride2026-03-113-7/+66
| | | | | | | | | | | | | | | | - Use fuse_passthrough_open/close API instead of raw fd assignment to fi->backing_id, which caused EIO on every file open through the VFS - Remove LD_LIBRARY_PATH from launcher script — DT_RPATH handles lib resolution, and LD_LIBRARY_PATH triggers AT_SECURE which drops file capabilities (cap_sys_admin) needed for passthrough - Auto-detect missing cap_sys_admin at mount time and prompt via pkexec to re-apply it (handles binary copy/update/extract losing the cap) - Disable passthrough for session if fuse_passthrough_open fails, avoiding "Operation not permitted" spam in terminal - Fix Nix flake: tinyxml2 → tinyxml-2, xorg.lib* → top-level names - CI: eliminate artifact zip round-trip for GitHub releases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* FUSE VFS performance, tracked writes fix, remove steam-run, add NixOS flakeSulfurNitride2026-03-1113-92/+283
| | | | | | | | | | | | | - FUSE: disable AUTO_INVAL_DATA, enable readdirplus, 24h TTLs, clone_fd, FUSE_USE_VERSION=312 — cuts game load time from 2:40 to 1:57 - Fix tracked writes going to wrong (lower-priority) mod in both detectManualMoves and syncOverwrite - Remove steam-run entirely (UI, C++, Rust layers) - Build system: default to tarball, add installer/appimage as opt-in modes - Add flake.nix for NixOS — builds from source with Rust crates as separate pure derivations, FHS wrapper, NixOS module with FUSE passthrough Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Track files moved from Overwrite to mods for in-place write-backSulfurNitride2026-03-1010-21/+769
| | | | | | | | | | When users move generated files (logs, INIs) from Overwrite into a dedicated mod folder, future VFS writes to those files now go directly to the mod instead of creating duplicates in Overwrite. Tracking persists across sessions via a JSON file and detects manual moves by comparing overwrite snapshots between sessions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove COW from FUSE VFS — write mod files in-placeSulfurNitride2026-03-092-106/+8
| | | | | | | | Mod .ini/.log files now stay in their original mod folder instead of being copied to Overwrite. All files pass through reads and writes to their real location. No copy-on-write needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* FUSE VFS: lazy copy-on-write to prevent Overwrite folder pollutionSulfurNitride2026-03-092-24/+74
| | | | | | | | Defer COW from open() to first write(). Wine/Proton opens mod files O_RDWR for metadata ops (SetFileTime, etc.) without actually writing, which was copying SKSE plugin .ini/.log files into Overwrite needlessly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Extract icons from .exe files for desktop shortcuts, add cache invalidationSulfurNitride2026-03-081-26/+295
| | | | | | | | | Parse PE resources to extract the largest embedded icon from Windows executables and save as PNG to ~/.local/share/icons/fluorine/. If a cached icon is just the Fluorine fallback (same file size), re-attempt extraction in case the executable changed or was previously unavailable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix LOOT sort for PluginsTxt games, improve desktop shortcuts, add Browse VFSSulfurNitride2026-03-087-25/+201
| | | | | | | | | | | | | | | | | | | LOOT sort fix: For PluginsTxt games (FO4, SkyrimSE), LOOT only modifies plugins.txt, not loadorder.txt. Previously the stale loadorder.txt was copied back, causing readPluginLists() to use the old order. Now we regenerate loadorder.txt from the sorted plugins.txt. Desktop shortcuts: Add "Application Launcher" option on Linux that creates .desktop entries in ~/.local/share/applications/. Include instance name in both filename (New-Vegas-NVSE.desktop) and Name= field (NVSE (New Vegas)) to avoid collisions. Icons saved to ~/.local/share/icons/fluorine/ with game-specific names. Browse VFS: Add button in Data tab that mounts the FUSE VFS and opens the game Data folder in the system file manager, allowing users to browse the merged mod files as the game sees them. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Remove FUSE passthrough (CAP_SYS_ADMIN incompatible with AppImage), remove ↵SulfurNitride2026-03-081-2/+5
| | | | | | | | | | | bsplugins, fix bsatk types - Remove FUSE passthrough code: requesting FUSE_CAP_PASSTHROUGH without CAP_SYS_ADMIN caused session cleanup crash on shutdown - Remove bsplugins library (unneeded port) - Fix bsatk: use uint32_t instead of unsigned long for BSAULong (LP64 compat) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* FUSE VFS performance: attr cache, selective invalidation, init tuningSulfurNitride2026-03-085-89/+861
| | | | | | | | | | | | - Increase ATTR_CACHE_SECONDS from 1.0s to 30.0s (90% getattr reduction) - Replace nuclear clearDirCache() with selective invalidateDirCache() that only clears the affected parent directory instead of all caches - Add mo2_init callback: enable FUSE_CAP_AUTO_INVAL_DATA for kernel page cache retention across open/close, increase max_readahead/max_write to 1MB - Switch open_files_mutex to shared_mutex for concurrent read access - Add perf handoff doc for VFS optimization history Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix LOOT sort copy-back, add Linux desktop shortcuts, remove Start MenuSulfurNitride2026-03-075-35/+182
| | | | | | | | | | | | | | | | | - Fix LOOT sorted order not applying: prefer Plugins.txt (capital P) over our pre-deployed plugins.txt (lowercase) since LOOT writes capital P on Linux case-sensitive FS. Same for Loadorder.txt. - Force plugin list refresh after LOOT sort (refreshESPList(true)) - Remove Start Menu shortcut option on Linux (no-op, Windows-only concept) - Implement .desktop file creation for Desktop shortcuts on Linux: - Use $APPIMAGE env var for stable executable path (not ephemeral mount) - Quote paths with spaces in Exec line - Use absolute instance directory path for portable instances - Install Fluorine icon to ~/.local/share/icons/ for persistence - Skip .exe icons (can't render on Linux) - Fix moshortcut:// instance matching for portable instances using abs paths Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix LOOT integration: FileTime support, VFS timestamps, perf, and overwrite ↵SulfurNitride2026-03-077-38/+323
| | | | | | | | | | | | | | | | pollution - Fix VFS files/dirs showing 1969 dates (separate error codes for mtime, set dir timestamps) - Add stampPluginTimestamps() for FileTime games (FalloutNV/FO3/Oblivion) so LOOT sees correct load order - Fix LOOT masterlist URL (v0.21 → v0.26) and point local_path to Fluorine prefix AppData - Capture FileTime-based load order from VFS timestamps before unmount - Handle Plugins.txt case sensitivity on Linux (LOOT writes capital P) - Skip loadorder.txt copy-back for FileTime games to preserve sorted order - Prevent LOOT COW'd plugins from polluting overwrite (discardStagingOnUnmount flag) - Update mo2_setattr to modify VFS tree mtime in-place without triggering COW - VFS perf: replace fs::relative() with fast string prefix strip, cache clock offset, parallel mod scanning Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Replace lootcli with standalone LOOT GUI AppImage on LinuxSulfurNitride2026-03-0712-18/+725
| | | | | | | | | | | | | | | - Download LOOT AppImage from GitHub releases on first sort - Pre-seed LOOT settings.toml with game type, path, and masterlist URL - Mount FUSE VFS before launching LOOT, unmount after exit - Copy plugins.txt/loadorder.txt to LOOT local path and back - Fix VFS file timestamps (separate error_code for mtime) - Add directory timestamps to FUSE (was showing 1969) - Stamp plugin files with load-order-based incrementing timestamps - Remove WebEngine dependency on Linux (QTextBrowser fallback) - Enable LOOT sorting for FalloutNV and FalloutTTW - Add unmountVFS() to OrganizerCore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Make overwrites the highest priorityOleg2026-03-071-5/+5
| | | | | | Overwrites were loading just after base files before mods themselves, meaning mods will overwrite everything in overwrites (which contradicts purpose of overwrites folder).
* Use direct stderr for VFS timing logs and filter Wine/Proton noiseSulfurNitride2026-03-053-16/+39
| | | | | | | | | - Switch VFS timing logs from log::info() to fprintf(stderr) so they always appear in terminal regardless of configured log level - Filter noisy Wine/Proton stderr output (GStreamer warnings, ProtonFixes info, RADV conformance, MangoHud, NTSync messages) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add VFS deploy and mount timing logsSulfurNitride2026-03-022-12/+63
| | | | | | | | | | | | | | Log timing for each phase of VFS setup and teardown at info level: - Base game file scan (fresh vs cached) - VFS tree build (file/dir counts) - External mapping deployment (symlink/file counts) - FUSE mount (total) - Staging flush on unmount - Full unmount - updateMapping total - Post-run permission restore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Restore game directory permissions after each runSulfurNitride2026-03-021-0/+17
| | | | | | | | In rare cases (crashes, unclean Wine shutdown), game files can end up read-only. As a precaution, restore owner rwx permissions on all files in the game directory after every run, right after FUSE unmount. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix VFS staging permissions and createTarget routingSulfurNitride2026-03-022-14/+35
| | | | | | | | | | | | | | | | | Two fixes: 1. copyOnWrite() preserves source file permissions via fs::copy_file(). If the source was read-only (Steam game files, Windows mod archives), the staging copy was also read-only, causing writes to fail with EACCES. Now adds owner_write permission after copying. 2. createTarget from the saves mapping (which targets __MO_Saves in My Games, not the Data dir) was incorrectly setting m_customOutputDir, causing ALL VFS staging files to flush to the profile saves directory instead of overwrite. Now only data-dir mappings can set the custom output directory. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix wineserver tracking matching unrelated wine prefixesSulfurNitride2026-03-011-11/+57
| | | | | | | | | | | | | findWineserver() was scanning /proc for ANY wineserver owned by the current user. If the user had other wine processes running (e.g. winecfg under ~/.wine), Fluorine would latch onto that unrelated wineserver and never declare the game finished. Now reads WINEPREFIX from the launched process's /proc/<pid>/environ and passes it to findWineserver(), which filters candidates by matching their WINEPREFIX against the game's prefix path. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>