| Commit message (Collapse) | Author | Age | Files | Lines |
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Shrinks the staging tree by ~27 MB (~250M -> ~223M) via two changes in
docker/build-inner.sh:
1. PyQt6 prune. Allowlist QtCore/QtGui/QtWidgets/QtOpenGL/QtOpenGLWidgets
(confirmed by full-repo grep of all shipped Python plugins). Drop the
remaining ~30 .abi3.so bindings plus bindings/, uic/, lupdate/, every
.pyi stub, every __pycache__. Pruning runs BEFORE the existing
ldd-scan loop, so libQt6Designer/Help/Sql/Test/SvgWidgets/Bluetooth/...
stop getting pulled into lib/ as a side effect.
plugins/libs/PyQt6: 31M -> 14M.
2. Dedupe lib/. cp -Lf on globs like libboost_program_options.so* stages
the unversioned soname and the versioned SO as identical real files.
Adds a post-bundling pass that, for each *.so / *.so.N file, finds a
byte-identical versioned twin via cmp -s and replaces it with a
symlink. Skips existing symlinks. Fixes the boost_program_options,
boost_thread, and xcb-cursor duplicates that have been here from the
start.
Also removes the now-orphan fluorine_vfs.dll / fluorine_vfs_hid.dll /
libfluorine_vfs_preload.so staging block left behind after the VFS shim
removal in 2ed0704f.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Dockerfile: drop apt python3/python3-pip, copy the uv static binary from
ghcr.io/astral-sh/uv:latest, install python-build-standalone via
`uv python install` (replacing the manual curl), run aqtinstall via
`uv tool run`, install build-time packages via
`uv pip install --system --break-system-packages --python ...`. Same swap
applied to the CI workflow's inline package-install step.
plugin_python: convert pyproject.toml from [tool.poetry] to PEP 621
[project] + [dependency-groups], drop poetry.lock, replace
abatilo/actions-poetry + `poetry install/run` with astral-sh/setup-uv +
`uv sync/run` in libs/plugin_python/.github/workflows/linting.yml.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Contains the following changes:
* Older mod formats (v15 and v16) supported
* Less strict meta.lsx parsing (empty values will use the default for
the type)
* zstd compression support
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Fluorine Manager launcher .desktop declared
MimeType=x-scheme-handler/nxm;x-scheme-handler/modl;, advertising itself
as a handler alongside the real mo2-nxm-handler.desktop. The launcher's
Exec line has no %u, so when xdg-desktop-portal launched it the URL was
dropped and MO2 came up with no args — which then hit the "instance
already running" path against the live primary. Drop the bad MimeType
from both the tarball template (data/icons/) and the .bin installer's
inline desktop entry in docker/build-inner.sh.
That alone fixes new installs, but xdg-desktop-portal remembers user
picks in its permission store: anyone who'd already selected Fluorine
Manager in the chooser dialog had it stuck as their always-use app
(count=3/3 = silent always-launch), and the bad pick survived removing
the MimeType. On startup the nxm handler now fires a DBus
DeletePermission against PermissionStore for com.fluorine.manager on
both schemes, so existing users self-heal on the next launch. The call
is fire-and-forget — a missing entry is the expected steady state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- OrganizerCore: add fluorineUpdater() getter + checkForSlrUpdates()
fired from startup checkForUpdates(); detached thread runs downloadSlr
when SLR already installed so steamrt4 BUILD_ID drift is picked up
without a launch-time stall.
- MainWindow: connect FluorineUpdater::updateAvailable to existing
updateAvailable() slot so the statusbar badge + actionUpdate light up;
on_actionUpdate_triggered routes to Settings -> Updates when a Fluorine
update is pending (the MO2 self-updater path is no-op'd).
- MainWindow launch path: drop !isSlrInstalled() short-circuit; fresh
installs still get the progress dialog, up-to-date checks rely on the
startup background pass.
- SettingsDialog: selectTabByLabel() so MainWindow can open Updates tab.
- Launcher: rm -rf update-staging/ once a new bundle has synced into
bin/, so the in-app updater doesn't accumulate stale extracts.
- CMakeLists.txt: 0.1.4 -> 0.2.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We ship via portable tarball directory + .bin self-extracting installer
only; the AppImage path was unmaintained and pulling in linuxdeploy
tooling for a format we no longer publish.
Build:
- build.sh: drop appimage/all-includes-appimage modes (now: tarball,
installer, all=both, shell). Output listing tracks the directory.
- docker/Dockerfile: drop BUILD_APPIMAGE arg and the linuxdeploy
download/extract block.
- docker/build-inner.sh: drop build_appimage() (~120 lines), AppImage
arm of the BUILD_MODE switch, *.AppImage summary listing.
- docker/AppRun.sh: deleted.
- .gitignore: drop *.AppImage / squashfs-root / *.flatpak entries.
Runtime: no longer key off APPIMAGE/APPDIR env vars or AppRun-set
state. The fluorine-manager launcher script already exports
FLUORINE_ORIG_*, MO2_BASE_DIR, MO2_PLUGINS_DIR, MO2_LIBS_DIR,
MO2_PYTHON_DIR for the same purpose, so simplify:
- envshortcut: appImageOrBinary -> launcherOrBinary; bundledFluorineIcon
no longer probes APPDIR.
- nxmhandler: drop APPIMAGE-based wrapper path; use applicationFilePath.
- protonlauncher: rename cleanAppImageEnv -> cleanFluorineEnv, drop
APPIMAGE/APPDIR/OWD/ARGV0/APPIMAGE_ORIGINAL_EXEC/DESKTOPINTEGRATION
removals and .mount_Fluori pattern strip.
- prefixsetuprunner: same env-cleaning trim.
- utility, library.h, proxypython, mainwindow, moapplication, appconfig:
comment cleanup pointing at the launcher instead of AppRun.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Replaces legacy API-key flow with OAuth 2.0 PKCE (public client,
client_id "modorganizer2", overridable via MO2_NEXUS_CLIENT_ID env).
Backwards-compatible: stored API key is used as fallback if no OAuth
token is present.
Fixes the symptom users hit after Nexus deprecated personal API keys
for download endpoints — Settings showed "Connected." (key still
validates) but downloads/CDN list returned empty.
Cherry-picked from upstream/dev/oauth-graphql against merge-base
925bade3, with these adjustments for our Linux-only fork:
- Dockerfile: aqtinstall +qtnetworkauth module
- CMakeLists.txt: find_package + link Qt6::NetworkAuth
- Dropped Windows-only hunks: dlls.manifest.qt6{,debug}, pch.h
QWebSocket include
- Skipped src/CMakeLists.txt and .gitignore upstream hunks (their
layout differs from ours)
- Skipped organizer_en.ts (regenerable via lupdate)
- Skipped tutorials/tutorial_firststeps_settings.js (defer to the
tutorials-disable PR port)
- Kept our defensive default member initialisers in
nxmaccessmanager.h (m_Reply{nullptr}, m_Result{None}, etc.) and
`override` on createRequest()
- Resolved trivial conflicts in modlistviewactions.cpp by taking
upstream's NexusOAuthTokens API while retaining our [=, this]
capture style
- createinstancedialog.h, instancemanager.cpp: only meaningful PR
delta is a comment text change / unrelated drift; ours retained
OAuth callback uses local loopback http://127.0.0.1:28635/callback
served by QOAuthHttpServerReplyHandler (no firewall punch needed).
Token storage piggybacks the existing Linux QSettings INI credential
backend (~/.config/ModOrganizer/credentials.ini).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Fixes #64: VFS now tracks the directories it creates outside the data
dir (external mappings + RootBuilder game-root deploys) and removes
them on unmount, but only if still empty. Pre-existing user dirs and
the game root itself are never touched. RootBuilder manifest gains a
"dirs" field so the cleanup survives a crashed session.
Also drops a Path-repr qDebug in bg3_file_mapper that crashed Qt's
logger on surrogate-escaped paths, and defaults QT_LOGGING_RULES to
default.debug=false in the launcher and AppRun (still overridable) so
the same class of plugin bug stays muted in shipped builds.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`./lint.sh` runs clang-tidy inside the fluorine-builder Docker image so
the toolchain matches what compile_commands.json was generated with.
Strips -mno-direct-extern-access (gcc-only) before invoking clang and
skips browserview/browserdialog since QtWebEngine is Windows-only in
this fork.
Scope: src/src/ + libs/skse_log_redirector/ (everything we authored).
Vendored upstream libs follow their own coding standards and stay
out-of-scope.
Default-off the noisiest categories (fuchsia/google/llvm/altera,
pro-type-*, magic-numbers, named-parameter, function-cognitive-
complexity, identifier-length, etc.) so the surfaced warnings are
actionable.
Dockerfile: install clang-tidy alongside the build deps so the image
ships everything lint.sh needs.
Usage:
./build.sh tarball # build the image (one-time after this commit)
# and produce compile_commands.json
./lint.sh # lint everything
./lint.sh --fix # apply auto-fixes
./lint.sh src/src/foo.cpp # lint a single file
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Removes every #ifdef _WIN32 / #ifndef _WIN32 / Q_OS_WIN block from the
organizer source tree. The Linux build is the only target this fork
produces, so the dead Windows branches were just noise. Stubs for
Win32-shaped APIs that the upstream code references (FILETIME, HANDLE,
DWORD, etc.) live in shared/windows_compat.h so the surrounding source
keeps compiling without rewriting every signature.
Also:
- Reimplemented env::DirectoryWalker / env::forEachEntry / env::Module
/ env::Process / env::WindowsInfo as Linux-only (uname, /etc/os-release,
/proc, std::filesystem) since the Win32 branches that previously held
those implementations are gone.
- Reduced spawn.cpp / processrunner.cpp / env.cpp to their Linux paths;
dropped the helper:: namespace, Win-only waitForAllUSVFSProcesses-
WithLock(), Steam Win-registry probe, and Windows mini-dump path.
- Linux launcher uses BUILD_JOBS (default 4) so docker rebuilds during
the audit don't pin the host.
Build verified after every batch with ./build.sh tarball.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Three FileMapper variants — Steam SSE, GOG, VR — that redirect
<docs>/My Games/<X> onto a sibling folder so SKSE writes logs to the
right place. Only one applies per game; all default off so the user
opts in to the matching variant.
Layout mirrors game_bethesda: shared static lib in src/common/ with the
QObject base (init/author/version/settings/enabledByDefault/mappings),
three plugin .so subdirs each adding Q_PLUGIN_METADATA + their own
name/description and destFolderName override. Q_PLUGIN_METADATA can
only appear once per .so, hence the split.
Paths preserved verbatim from the upstream .py — including the SSE
variant's "Skyrim.INI" sibling folder, which is intentional: a Skyrim
bug sometimes creates a directory of that name and the redirect makes
SKSE find logs in SSE's docs folder.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The version-sync step wiped ~/.local/share/fluorine/bin/ wholesale
before staging the new bundle in, which destroyed any user content
sitting alongside ours: portable instances (ModOrganizer.ini lives in
bin/ via MO2_BASE_DIR), custom plugins under bin/plugins/, etc.
Replace the wipe with a manifest-driven overlay: orphan top-level
entries we no longer ship get removed, then tar streams the manifested
entries from the extracted bundle on top of the live dir. Existing
directories are kept; user-added files inside our directories survive
because tar -x only writes paths it sees in the input stream.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- VFS: add mo2_rmdir + OverwriteManager::removeDirectory so Wrye Bash
shutil.rmtree stops failing with WinError 267 (issue #47).
- FileRenamer: case-insensitive fallback via new resolvePathCaseInsensitive
walks each path component; bulk hide in Conflict tab no longer dies with
a misleading "Input/output error" when DirectoryEntry normalised parent
dir case (issue #54). formatSystemMessage stops aliasing Windows error
code 5 to errno 5 (EIO).
- Versioning: FLUORINE_VERSION_* + fluorine_build_info.h generated from
CMake; Linux createVersionInfo returns Fluorine's version. About dialog
shows Fluorine version + MO2 engine + commit. Beta builds stamp
"<semver>B<yyyymmddhhmm>" (issue #51).
- CI: ci.yml determines channel from ref (v* tags = stable, main = beta),
publishes a rolling `beta` GitHub release whose body carries a
machine-parseable fluorine-meta block (timestamp, commit) for the
in-app updater.
- Updater: new FluorineUpdater polls GitHub API on startup, compares
against embedded metadata, notifies on new release without auto-install.
Channel toggle piggybacks on the existing "beta versions" checkbox.
- Bethesda plugins: determineMyGamesPath no longer creates
Documents/My Games/<GameName> for every possible title at plugin load;
only games with a detected install path get their dirs created
(issue #55).
- Starfield: dataDirectory() on Linux now points at <game>/Data instead
of My Games/Starfield/Data so the single FUSE mount lands where SFSE
loads plugins; My Games Data becomes a secondary symlinked mapping
(issue #56).
- Prefix resolution: prefer Fluorine config, then explicit
fluorine/prefix_path, then legacy Settings/* keys (with a warning) so
auto-detected Heroic/Bottles prefixes can't silently override a user-
configured Fluorine prefix (issue #52). compatDataPathFromPrefix no
longer hands Proton the wrong parent dir for plain wine prefixes.
- xrandr: ensureXrandrInstalled back-fills the helper for existing SLR
installs, prefix init runs it before wineboot, SLR wrap exposes
xrandr-bin via --filesystem= and prepends PATH inside the container
(issue #49).
- Process tracking: drop the wineserver-as-last-resort fallback that made
MO2 hang on Proton's session manager after game exit. Rescan the prefix
for matching game executables instead (covers reparented launcher
children like f4se_loader → Fallout4.exe). Unlock button now kills
wineserver for the prefix (SIGTERM then SIGKILL on timeout).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- Replace copy-in/copy-out save deployment with a direct symlink from the
prefix's __MO_Saves to the profile's saves/. Writes land in the profile
immediately; afterRun reverts the symlink + prefix INI so a vanilla
launch outside MO2 uses the default Saves dir.
- Parse Steam's binary appinfo.vdf (v41) via a new Rust FFI crate backed
by steam-vdf-parser. Rank detected games by common.type so real Games
beat Tools/Editors when multiple prefixes share a My Games folder name
(fixes Creation Kit shadowing Skyrim SE). Top-ranked candidate
overwrites stale symlinks from earlier runs.
- Switch bundled Steam Linux Runtime downloader from sniper (steamrt3)
to steamrt4 so Proton 11+ works out of the box. steamrt4 omits xrandr
so we inject it from the Debian x11-xserver-utils .deb into a
dedicated dir and prepend it to PATH via `env PATH=...` inside the
pressure-vessel container (PATH env doesn't propagate).
- Auto-kill stale wineboot/wineserver/pv-adverb processes still bound
to the prefix before starting a new wineboot -u; match by
/proc/<pid>/environ WINEPREFIX / STEAM_COMPAT_DATA_PATH since Wine
cmdlines are Windows-style. Same sweep runs in destroyPrefix so a
delete actually frees file handles.
- Blacklist Proton 11 (Steam-bundled) — its current Wine tree deadlocks
during wineboot -u on modern kernels via ntsync / futex_wait_multiple
races. Use "waitforexitandrun" (not "run") for prefix init so
use_sessions=1 Protons don't fork into a persistent session manager.
- Drop WINEDEBUG=-all during prefix init so wineboot progress is
visible. Suppress focus-stealing by setting WA_ShowWithoutActivating
on the PrefixSetupDialog and SLR download progress dialogs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
VFS:
- Open backing fd at mo2_open time for read-only handles so mo2_read can
splice without re-opening the file on every read call.
- Bump RLIMIT_NOFILE at mount time to fit the resulting fd pressure when
the game keeps hundreds of BSAs open.
- Dedicated node_cache_mutex so resolveByInode / mo2_lookup stop racing
unordered_map writes while multiple tree_mutex readers are active.
- max_read=1MB + matching conn->max_read and raised max_readahead/max_write
so the kernel merges Wine's small sequential reads into bigger FUSE
requests.
- Per-op wall-clock counters in mo2_init() logs so we can distinguish VFS
latency from game-side work.
Proton launch:
- Write dxvk.conf to the prefix and set DXVK_CONFIG_FILE to force
dxvk.enableGraphicsPipelineLibrary=False, avoiding long GPL compile
stalls on first run.
UI / plugin compat:
- Clamp IconDelegate's per-icon width to [8, 16] so narrow content
columns don't trigger QIcon::pixmap(0,0) returning null and logging
"failed to load icon" every repaint.
- Pre-create lowercase symlinks in the stylesheet directory so QSS files
authored on Windows resolve url(foo.svg) when on-disk files are Foo.svg.
- Flip content icons empty-chessboard.png and facegen.png to 8-bit RGBA
so Qt's built-in PNG reader loads them uniformly.
- Add mobase.Version.canonicalString shim for legacy Python plugins that
still call the old VersionInfo method on appVersion()'s return.
- BSPluginList: compare normalized plugin name lists instead of byte
hashes so the post-run case-fix refresh stops spuriously firing the
"load order changed" dialog.
- BSPluginList disabled by default.
Download manager:
- Parse CDN URL with QUrl + QUrlQuery and read the filename from the
response-content-disposition query param (RFC 6266 quoted / unquoted /
ext-value forms), not QFileInfo on the raw URL.
- When the API or URL gives us a CDN object key (no archive extension),
prefer the actual Content-Disposition header from the live response in
metaDataChanged and downloadFinished.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
bsatk:
- Archive::extractToMemory() extracts a file directly into a byte buffer
instead of a filesystem path, backed by a std::ostringstream sink.
- Archive::findFile() locates a file by relative path, case-insensitive
and separator-agnostic, walking the folder tree recursively.
- extractDirect/extractCompressed now take std::ostream& so both the
ofstream and ostringstream paths share the same implementation.
libbsarch: shim rewrite on Linux to map the Windows API surface onto
bsatk::Archive, enabling preview_bsa to open vanilla BSAs via the
same interface as other plugins.
preview_bsa: double-click on a file in the BSA tree now extracts the
bytes via extractToMemory() and hands them to IOrganizer::previewFileData
for nested preview rendering (e.g. NIF inside a BSA).
uibase + organizerproxy + organizercore: new IOrganizer::previewFileData
virtual that routes in-memory file bytes through the first registered
IPluginPreview matching the extension. Uses heap + WA_DeleteOnClose +
open() to avoid nested exec() softlock from mod info filetree ->
preview_bsa tree -> nif preview.
docker/build-inner.sh: stage preview_nif shaders into plugin_data/shaders
so ShaderManager can load them via IOrganizer::getPluginDataPath().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
actions/upload-artifact@v4 defaults include-hidden-files to false, so
.fluorine-manifest was getting stripped from the CI release artifact
and users saw the launcher bail with "can't find its bundle files"
despite the build log reporting "Wrote manifest: 10 entries".
Rename to fluorine-manifest.txt. Sidesteps the upload-artifact default
and also survives any user-side extractor that hides dotfiles.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Previous sync ran `tar -cf - .` inside the launcher's HERE dir, which
slurped anything sitting next to the fluorine-manager script. If a user
extracted the release archive into ~/Downloads (alongside a 38 GB mod
stash), the launcher happily copied the whole lot into
~/.local/share/fluorine/bin/ on first run.
Write a `.fluorine-manifest` at build time listing the top-level entries
that belong to Fluorine, then have the launcher copy only those entries.
Also bail with a clear error if the manifest or ModOrganizer-core is
missing — catches "launcher dropped into some random folder" before any
damage is done.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Version fingerprint was stat -c '%i:%Y' which includes the inode number.
Re-extracting the same tarball produces new inodes, so the marker never
matched and the 237MB copy to ~/.local/share/fluorine/bin/ ran on every
launch — painful cross-drive (tarball on one disk, home on another).
Switch to '%s:%Y' (size + mtime). Survives re-extraction, still detects
real updates.
Also stage into bin.new/ and rename instead of rm -rf'ing bin/ before
the tar pipe. If the user Ctrl+C's mid-sync (or the copy fails), the
existing install stays intact instead of being left empty.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The sort button was already hidden on Linux (setVisible(false)) and
the LOOT feedback path (LootDialog -> addLootReport) has always been
Windows-only, meaning the dirty/incompatibilities/missingMasters/messages
tooltip bullets and the dirty-plugin icon could never fire on Linux.
MO2 shipped lootcli + libloot for a load-order sort mechanism that was
unreachable from the UI.
Users who want LOOT can download it from https://github.com/loot/loot
and run it against their instance directly.
- Drop libs/lootcli/, libloot Dockerfile build step, and lootcli
staging/patchelf in build-inner.sh
- Drop src/src/loot.{cpp,h}, src/src/lootdialog.{cpp,h,ui}
- Extract MarkdownDocument / MarkdownPage (used by UpdateDialog for its
changelog view) into src/src/markdowndocument.{h,cpp}
- Strip addLootReport, makeLootTooltip, Loot::Plugin field, LOOT icon
checks, and LOOT tooltip/isProblematic/hasInfo paths from pluginlist
- Delete sortButton widget, updateSortButton(), onSortButtonClicked(),
and all m_didUpdateMasterList wiring
- Delete lootLogLevel setting, combo box, and "Integrated LOOT" group
from the diagnostics settings tab
|
| |
|
|
|
|
|
| |
PyQt6 6.11.0 requires Qt_6.11 symbols not present in our bundled
Qt 6.10.2, causing all Python plugins to fail with ImportError.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Replace NaK Rust crate and nak_ffi with native C++ implementations:
- Game detection (Steam, Heroic, Bottles), VDF parser, icon extraction
- Prefix symlinks, SLR manager, Steam path detection
- Known games database
Add FUSE VFS optimizations: zero-copy reads via fuse_reply_data,
default_permissions mount option, FUSE_CAP_ASYNC_DIO, FUSE_CAP_EXPIRE_ONLY,
lookup cache parent index, cached mode bits, increased I/O buffer sizes.
Update build system, prefix setup, and various fixes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Direct DLL extraction and installer execution instead of shelling out
to winetricks for all prefix dependencies. Fixes d3dcompiler_47 being
sourced from wrong SDK cabs (broke CommunityShaders), and eliminates
the fragile cabextract-in-pressure-vessel PATH issue.
- d3dcompiler_47: direct download from Mozilla fxc2 repo
- d3dcompiler_43, d3dx9, d3dx11_43: cabextract from DirectX June 2010
redist with correct system32/syswow64 mapping
- xact/xact_x64: cab extraction + batched regsvr32 registration
- vcrun2022: direct installer with msvcp140.dll workaround (Wine #57518)
- dotnet6/7/8, dotnetdesktop6: direct x86+x64 installer pairs
- Game detection: batched into single .reg file import
- All DLL overrides added to WINE_SETTINGS_REG
- SHA256 verification for downloaded files
- Winetricks kept only for win11 mode step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
env var detection
Steam game mode injects its scout/soldier runtime into LD_LIBRARY_PATH,
which breaks Python extension modules and Qt internals that resolve
dependencies via LD_LIBRARY_PATH rather than RPATH. This caused all
Python-based basic_games plugins (Witcher 3, Oblivion Remastered, BG3,
etc.) to fail to load when launched through Steam.
Changes:
- Launcher script: set LD_LIBRARY_PATH to only bundled lib/ dir instead
of leaving Steam's runtime in the path
- AppRun: same fix — replace rather than append to LD_LIBRARY_PATH
- Deploy libbasic_games_native.so in tarball (was built but never copied)
so basic_games entries work without Python dependency
- Add STEAM_COMPAT_CLIENT_INSTALL_PATH env var check to Python
steam_utils.py (mirrors C++ fix from e41a79a) for game mode detection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Qt platform plugins (libqxcb.so, libqxcb-glx-integration.so, etc.) kept
aqtinstall's hardcoded RPATH (/opt/qt6/6.10.2/gcc_64/lib) which doesn't
exist on user systems. The linker fell through to system Qt, loading the
wrong version into the process link map. When PyQt6 bindings later loaded
libQt6OpenGLWidgets, glibc reused the already-cached system version, causing
private-API symbol mismatches against our bundled Qt 6.10 (seen on Mint,
Bazzite, and likely all distros with system Qt installed).
All Qt plugins are one subdir deep under qt6plugins/, so
$ORIGIN/../../lib correctly resolves to our lib/ for all of them.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
PyQt6 is staged after the main dep-collection loop, so its .so deps
(e.g. libQt6OpenGLWidgets) were never copied to lib/. The dynamic linker
then fell back to the host's Qt RPM build, which exports Qt_6.*_PRIVATE_API
version symbols that aqtinstall's Qt doesn't — causing a crash on Fedora-
based distros (Bazzite, etc.) whenever a Python plugin imported PyQt6 OpenGL.
Add a post-PyQt6 dep scan that bundles any Qt libs not yet present in lib/.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
Qt >= 6.5.0 requires libxcb-cursor0 to load the xcb platform plugin,
but it's frequently absent on user systems. All other libxcb libs are
skipped (must match host X server ABI), but libxcb-cursor is a pure
utility library safe to bundle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
- Stage DDS/ package from source directly to plugins/data/DDS/ in
build-inner.sh (cmake MO2_STAGE_PYTHON_PLUGIN_PAYLOAD is OFF by
default so the cmake-sourced path was silently skipped)
- Stage winreg.py from libs/ directly as well (same root cause)
- Guard `import winreg` in gog_utils.py with try/except ImportError
and early-exit to Heroic GOG path if the shim is unavailable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- 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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- 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>
|
| |
|
|
|
|
|
|
| |
NixOS/Arch users have Qt 6.10 system-wide, causing Qt_6.10 symbol errors
when loading mobase.so against the bundled Qt 6.9. Switch Docker build to
install Qt 6.10.2 from aqtinstall instead of Ubuntu's Qt 6.9 packages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
mobase.so in plugins/libs/ couldn't find bundled Qt/uibase because the
RPATH was only one level up (plugins/lib/) instead of two (lib/). This
caused "initialization failed" on NixOS and potentially other distros.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
The Python proxy expects mobase.cpython-313-x86_64-linux-gnu.so in
plugins/libs/ but build-inner.sh was not copying it. This caused
"No module named 'mobase'" when loading Python plugins.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- libs/rootbuilder_native/: Native C++ port of rootbuilder.py (IPluginTool)
- Root/ dir scanning, copy (reflink/CoW) and symlink modes
- JSON manifest tracking, backup/restore, auto-deploy hooks
- Legacy migration and third-party conflict detection
- libs/installer_omod_native/: Native C++ port of installer_omod.py
- Handles .omod archives (Oblivion Mod Manager format)
- Binary config parsing, .NET string format, CRC file parsing
- zlib raw deflate and LZMA decompression
- Repackages to zip for MO2's installation manager
- Added both to build-inner.sh plugin packaging
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|