| Commit message (Collapse) | Author | Age | Files | Lines |
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
meta.ini: Qt6 QSettings IniFormat is case-sensitive on Linux. Pre-existing
CamelCase keys + lowercase setValue() left both casings in the file, so
mods grew duplicate entries on every install. Added MetaIniUtils::
normalizeMetaIniCase() to fold keys to lowercase and dedupe per-section
(keeping non-empty values) before any QSettings open in readMeta,
saveMeta, doInstall, and createMod.
SKSE Log Redirector: deployExternalMappings created per-file symlinks
under the redirected destination, so any new log file the game wrote
post-deploy ended up as a real file outside the mapping. For
isDirectory && createTarget mappings, now publish a single directory
symlink dst -> src when the destination is missing, an existing symlink,
or empty. Falls back to per-file symlinks when dst already has real
content (preserves user data). Cleanup removes the symlink, leaving no
files behind.
Tests under src/tests/ (gtest, opt-in via BUILD_TESTING):
- test_metainiutils: 6 tests covering no-op cases, case-only dedup,
multi-line continuations, per-section scoping, and end-to-end
verification that QSettings duplication is fixed.
- test_external_dir_mapping: 6 tests covering directory symlink deploy,
flow-through writes, idempotency, empty-dir replacement, real-file
fallback, and cleanup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Cherry-picked the three preview-parent fixes from #2368:
parentWidget() in ConflictsTab/FileTreeTab/ImagesTab returns the tab
widget itself, not the dialog — preview windows ended up parented to
the wrong widget. m_parent->parentWidget() returns the actual mod info
dialog so previews position and z-order correctly.
Skipped the Starfield blueprint feature from the same PR — requires
coordinated changes across uibase (add IPluginGame::blueprintPrefix)
and modorganizer-game_bethesda (Starfield override). See
project_upstream_pending_prs.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds metadata flags to the `download` subcommand and a corresponding
DownloadManager::startDownloadURLWithMeta() entry point that populates
ModRepositoryFileInfo before queueing.
Skipped the upstream settings.cpp hunk that re-registers the Windows
nxmhandler.exe binary for both nxm:// and modl:// — our nxmhandler_linux
already registers both MIME schemes in registerHandler().
Cherry-picked from upstream/dev/modl-handler against merge-base dc420a25.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
| |
Distinguish between -i (no value, prints current instance and exits)
and -i "" (launches the portable instance if one exists) by switching
the option parser from std::string to boost::optional<std::string>.
Cherry-picked from upstream 49da80c.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
When MO2 is launched by the nxm handler from a browser, CWD is whatever
the browser inherited (often /, $HOME, or the user's Desktop). Reset it
to the application directory so any code path relying on CWD behaves
the same as a normal launch.
Cherry-picked from upstream f80ad04. Comment expanded for the Linux
context (Qt resource lookup, relative QFile paths, QtWebEngine sandbox
helper) — upstream's note only covered QtWebEngineProcess on Windows.
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>
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Final auto-fix sweep that adds const to local variables and switches
range-for-by-value to range-for-by-const-ref where the element type is
non-trivially-copyable.
The auto-fixer also emitted ~15 invalid \`for (const T& const x : ...)\`
range loops where \`const-correctness\` and \`for-range-copy\` both fired
on the same line. Hand-fixed via sed: \`& const \` -> \`& \`.
Build verified.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Sequentially applied a tighter set of safer checks:
- modernize-return-braced-init-list
- modernize-use-equals-default
- modernize-use-noexcept
- modernize-use-using
- modernize-raw-string-literal
- readability-enum-initial-value
- readability-make-member-function-const
- readability-convert-member-functions-to-static
- readability-redundant-member-init
- readability-container-contains
- readability-container-size-empty
One file (mainwindow.h) had to be hand-fixed: extractProgress was
auto-marked static by readability-convert-member-functions-to-static,
but it's bound via boost::bind(&MainWindow::extractProgress, this,
...) — making it static breaks the bind. Restored to a non-static
member.
Build verified.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The first auto-fix run kept going in the background after the wait
loop returned (a podman-detached quirk), so it produced another batch
of fixes against ~52 more files that needed verification.
Two cases the auto-fixer can't fix safely on its own:
- DWORD m_exitCode{-1} -> static_cast<DWORD>(-1) on the brace init,
because -1 narrows to unsigned int.
- {EndorsedState::X} / {TrackedState::X} initializers had to be
qualified with their parent namespace (MOBase::) because the
identifier wasn't in scope at the point of in-class default-init.
Build verified.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Ran sequentially (not parallel — concurrent fixes corrupt shared headers)
on src/src/ + libs/skse_log_redirector/. The check set:
- modernize-use-override
- modernize-use-nullptr
- modernize-use-default-member-init
- readability-redundant-member-init
- readability-container-contains
- readability-container-size-empty
Net effect: ~108 files updated, 425/426 lines changed (overrides added,
NULL/0 -> nullptr, member-init lists pruned where the same value is
already in the in-class default). Build verified after revert/re-apply.
Also disable readability-redundant-access-specifiers in .clang-tidy:
the check is confused by Qt's `private slots:` specifier and strips the
`private:` that follows it, breaking MOC.
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
These files were ported from upstream MO2 with the Windows code wrapped
in #ifdef _WIN32 and Linux equivalents in the #else branch. The Windows
branches never compile on this fork — drop them so the source matches
what's actually built.
- envwindows.cpp/.h: kept Linux uname()/os-release implementation; the
WindowsInfo::Version/Release fields drop their DWORD/uint32_t fork.
- envshell.cpp: deleted entirely (Linux body was empty — header
declares no-op stubs inline).
- envshell.h: drop Win32 ShellMenu declarations, keep Linux stubs.
- envmetrics.cpp: kept QScreen-based Linux Display/Metrics implementation.
- envshortcut.cpp: kept Linux .desktop shortcut writer + PE icon
extractor, drop Win32 IShellLink path.
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Setting UMU_ID="fluorine" triggered protonfixes' setup_mount_drives
(GE-Proton/utilities.py), which mounts X:=$HOME, U:=/media, V:=/run/media,
W:=/mnt every launch — undoing pruneExtraDrives. Wine's find_drive_nt_root
walks the path innermost-out and picks the first matching drive, so
X:=$HOME wins over Z:=/ for any path under home, producing X:\games\...
launches.
Empty UMU_ID:
- protonfixes utilities.py:38 `os.environ.get('UMU_ID','')` -> '' falsy
-> setup_mount_drives early-exits, no X/U/V/W created
- proton:1590 same falsy check -> 'gamedrive' not added to compat_config
-> setup_game_dir_drive's setup_dir_drive takes the elif branch and
actively removes any stale s: symlink
- proton:2340 `"UMU_ID" in os.environ` is still True for "" -> still
skips the c:\Program Files (x86)\Steam\steam.exe bridge for non-Steam
executables (the original reason we set UMU_ID)
Verified against installed Proton-GE proton script + utilities.py and
GloriousEggroll's confirmation in umu-launcher#634.
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>
|
| |
|
|
|
|
|
|
|
| |
Blanking DISPLAY/WAYLAND_DISPLAY made xrandr exit 1 inside the
container, which Proton-GE 10-34's protonfixes treats as fatal during
wineboot -u. wineboot -u is unattended and won't pop UI, so leaking the
host display vars is safe.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
New "Enable Steam Overlay" checkbox in Instance Manager (off by
default, key fluorine/steam_overlay). When enabled and the executable
has a Steam App ID, ProtonLauncher now:
- LD_PRELOADs gameoverlayrenderer.so (32+64 bit) from the running
Steam install for legacy GL/X11 hooks,
- sets SteamOverlayGameId so Steam's IPC handshake matches the app,
- exports ENABLE_VK_LAYER_VALVE_steam_overlay_1=1 and clears the
DISABLE_... counterpart so the Steam Vulkan implicit layer loads
even under pressure-vessel (this is what makes overlay work for
DXVK-rendered Bethesda games — most "manual" overlay setups skip
this and only get the GL hook),
- ensures Steam is running, and
- exposes <steam>/ubuntu12_{32,64} as SLR --filesystem= mounts so
the .so paths resolve inside the container.
No reaper wrapper, so Steam's "in-game" indicator may stay blank, but
the overlay itself attaches because the .so/Vulkan-layer hook the
process directly. Requires the user to actually own the game on the
running Steam account.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
| |
Pruning only the dosdevices symlinks let Wine recreate them on the
next prefix start from [Software\\Wine\\Drives] in system.reg, so
external mappings like X:=/home/user/Games kept winning over Z: when
Wine canonicalised launch paths (game spawned with X:\Games\... cwd
instead of Z:\home\user\Games\...). Strip those registry lines too.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
std::locale("") at static-init throws std::runtime_error on systems
where the requested locale (e.g. en_US.UTF-8) isn't generated, killing
Fluorine before main() runs. Wrap in try/catch and fall back to the
classic locale.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Wine canonicalises paths against the dosdevices map and prefers the most
specific (longest-prefix) drive letter. An external symlink such as
dosdevices/x: -> /home/<user> turns every Z:\home\<user>\... binary path
into X:\..., which confuses tools and obscures launch logs.
PrefixSetupRunner::stepDriveCleanup already enforces the {C:, Z:} policy
but only runs as part of the explicit prefix-setup pipeline; drives
added later (Faugus, manual edits, modlist installers) survive forever.
Mirror that cleanup at launch in spawn.cpp's pruneExtraDrives() so every
Proton launch sees a known-good dosdevices layout.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add IPluginGame::isNativeLinux() (virtual, default false) so a plugin
can advertise that the discovered installation is a native Linux build.
Bound through the Python plugin trampoline so basic_games subclasses can
override it.
Stardew Valley plugin: when the install dir contains the StardewValley
launcher script and no Stardew Valley.exe, report isNativeLinux=true and
return Linux-side binary names (StardewValley, StardewModdingAPI). Also
fix GameDataPath to "Mods" — Linux ships the SMAPI mods dir with a
capital M.
ExecutablesList::getPluginExecutables: skip the UseProton flag when the
plugin reports native Linux, so the spawn path falls into launchDirect()
and the game runs without a Wine prefix.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Wrap every FUSE callback in a noexcept thunk that catches std::bad_alloc
(→ ENOMEM) and other exceptions (→ EIO) so they never unwind into
libfuse3 (C, no unwind support). Stops std::terminate from orphaning
the mount.
Crash handler: replace raise(sig) with _exit(128+sig) — raise can hang
when the signal is masked on libfuse worker threads. Try direct
umount2(MNT_DETACH) before fork+exec fusermount3 -uz, and double-fork
the fallback so we don't waitpid on a stuck child. Switch signal() to
sigaction(SA_RESETHAND), add SIGBUS, install std::set_terminate.
Cap readdir/readdirplus kernel-supplied size at 1 MiB to defend against
oversized vector(size) allocations.
|
| |
|
|
|
|
|
|
| |
Last commit renamed the QProcess variable but missed the final
extractor->start(), breaking the build. No logic change beyond
completing the rename.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
GitHub Releases serves whatever's uploaded, but some CI flows produce
.zip artifacts (or users re-upload as zip). Teach the release-info
parser to pick up .zip when no .tar.gz is attached, and teach the
install flow to call `unzip` vs `tar` based on the URL extension.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds an "Install update & restart" button that:
1. Downloads the release asset (with progress bar).
2. Extracts tarball to ~/.local/share/fluorine/update-staging/extract/.
3. Writes a small install.sh helper that waits for the current Fluorine
PID to exit, then execs the new launcher.
4. Launches the helper detached and quits the current process. The new
launcher runs its existing sync-into-bin/ logic and starts from there.
Button stays disabled until a check has reported an update with a valid
.tar.gz asset attached.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
Upstream MO2 gates the one-time MO2 2.4 -> 2.5 category-migration dialog
on `lastVersion < 2.5`. Fluorine's 0.x.y schema change means lastVersion
is 0.x.y, which is always < 2.5, so the dialog nagged on every startup.
Skip it when lastVersion has major=0 (Fluorine).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- settingsdialogupdates.cpp missed an include of settings.h (it was only
getting the forward-declared version from settingsdialog.h), which
broke every settings().setX() call. Now included directly.
- UpdatesSettingsTab is not a QObject so it has no tr() member; add
Q_DECLARE_TR_FUNCTIONS to get a static tr() via QCoreApplication.
- CI: the docker run chained commands with `;` so a ninja failure got
masked by the trailing `ccache -s`. Capture the build-inner.sh exit
status and `exit $status` at the end so real build failures fail the
step instead of bleeding into the tar packaging step and producing a
confusing "Cannot stat: No such file" error.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- New Settings > Updates tab (src/src/settingsdialogupdates.{h,cpp}):
current build info (version, channel, commit, timestamp), channel
picker, startup-check toggle, and a "Check for updates now" button
with live status. Legacy widgets on the General tab are now hidden.
- Downgrade warning: suppress the "your version is lower than before"
log when lastVersion is 2.x.y (upstream MO2 / pre-Fluorine schema)
and currentVersion is 0.x.y — that's a schema switch, not a
downgrade.
- Titlebar: beta builds show "beta @ <short-sha>" instead of a static
semver so each rolling build is identifiable at a glance. Stable
still shows semver. Renamed to "Fluorine Manager" in the title.
- Controllers: remove the four xinput* "native" overrides from the
prefix registry seed. Games that ship their own xinput1_3.dll
(Fallout 4, Skyrim, etc.) make Wine's builtin (SDL-backed) lose to
a Windows stub that can't talk to /dev/input, so controllers went
silent. Leaving xinput unset lets Wine builtin win.
- ntsync fallback: detect a missing /dev/ntsync at launch and set
PROTON_NO_NTSYNC=1 / WINENTSYNC=0 / WINE_DISABLE_FAST_SYNC=1 so
pre-6.14 kernels stop dying with "Cannot open synchronization
device: No such file or directory".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
The docker build runs as root inside the container and the bind-mounted
build/ tree ends up root-owned on the runner. The runner-user tar step
then can't create the archive. Fix up ownership before packaging.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
Stable releases are cut manually against a tag (see CHANGELOG.md).
CI only publishes the rolling `beta` release now, so the always-skipped
Publish stable release step and the `v*` tag trigger were just noise in
the job graph.
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 the per-launch __MO_Saves symlink with a kernel bind mount
inside an unprivileged user+mount namespace. Writes from the game
land directly in the profile's saves dir via the mount, which Wine
can't replace with a real directory the way it could with a symlink.
The namespace (and therefore the bind) tears down automatically when
the game process tree exits, so afterRun no longer needs to sync
saves or undeploy anything. Fall back to the symlink path on
kernels where unprivileged_userns_clone is disabled (Debian buster,
linux-hardened); detection is via /proc/sys/kernel/unprivileged_userns_clone.
DownloadListView::issueDeleteSelected captured indices up-front and
looped emit removeDownload(row). DownloadManager::removeDownload
calls refreshList() at the end, which clears finished entries from
m_ActiveDownloads and rebuilds from disk enumeration — stale indices
after the first delete pointed at the wrong file or triggered the
invalid-index error. Capture filenames instead and re-resolve the
current row each iteration.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Wine picks its Unix codepage from LC_ALL/LC_CTYPE/LANG via
nl_langinfo(CODESET); a C/POSIX locale falls back to CP1252, so
non-ASCII Linux filenames (CJK, Cyrillic) fail UTF-8→UTF-16
conversion and MSVC std::filesystem throws "Invalid name" when
Windows tools like PGPatcher iterate mod dirs through the Z:\ drive.
Steam's pressure-vessel can strip the user locale, triggering this.
Detect UTF-8 in LC_ALL/LC_CTYPE/LANG and only inject C.UTF-8 when
none is UTF-8 already — preserves de_DE.UTF-8, ja_JP.UTF-8, etc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Bethesda Plugin Manager disabled in settings still swapped the espTab
at UI init — the callback ran unconditionally. Gate it on
isPluginEnabled and warn + flag restart when toggling panel plugins,
since the swap is one-shot.
Pre-deploy sync-back: if prefix Plugins.txt mtime is newer than
profile (external LOOT run), syncPluginsBack first so the deploy
doesn't clobber the external edits.
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>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Proton 11's toolmanifest sets use_sessions=1, so the "run" verb forks
into a persistent session manager that never exits — prefix init hung
forever. Use "waitforexitandrun" instead. Also drop WINEDEBUG=-all so
init output is visible, and migrate the bundled Steam Linux Runtime
downloader from steamrt3/sniper to steamrt4 (Proton 11's required
runtime). SLR lookup paths fall back to sniper for users with an
existing install.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
deployPlugins now writes only the plugin-list file the game actually
reads (Plugins.txt for PluginsTxt games, lowercase plugins.txt for
FileTime games). loadorder.txt is MO2-internal and never belonged in
AppData/Local/<Game>/; previously writing a stale copy there defeated
LOOT's edits because syncPluginsBack pulled the stale loadorder.txt
back into the profile, and getLoadOrder() preferred it over the
freshly-synced plugins.txt.
syncSavesBack now mirrors deletions: files present in the profile but
absent from the prefix are removed before the copy pass. Without this,
saves the user deleted in-game stayed in the profile forever because
copyTreeContents only copies files that exist in the source.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When stepProtonInit failed, the runner kept marching through every
downstream step against a half-initialized prefix, producing a cascade
of misleading "wine client error: version mismatch" failures that
masked the real problem. Seen in the wild with a GE-Proton10-34 install
that was missing concrt140.dll from its bundled default_pfx template:
setup_prefix crashes with FileNotFoundError, then seven unrelated steps
are reported as broken.
Break out of the step loop as soon as proton_init fails, and inspect the
captured Proton output for the "FileNotFoundError" + "default_pfx" hint
so the error message points at the broken Proton distribution instead
of a generic "exit code 1". runProcess gains an optional QByteArray*
out param so the caller can pattern-match on the merged output without
changing any existing call sites.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
OrganizerCore::modStatusChanged updates the DirectoryStructure in
place (enabling/disabling origins) but never fires
directoryStructureReady, which is the only signal MainWindow used to
drive DataTab::updateTree. Result: after enabling or disabling a mod
the Data tab kept showing the old virtual tree until the user hit
Refresh manually.
Connect ModList::modStatesChanged directly to DataTab::updateTree so
the file tree re-queries the structure as soon as the toggle lands.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
syncPluginsBack previously updated the profile from the newest case
variant but left the stale sibling (e.g. lowercase plugins.txt after
LOOT edited Plugins.txt) untouched in the prefix, so anything reading
the prefix before the next deployPlugins saw divergent content. Mirror
the newest variant into every sibling after the profile sync.
installer_omod.py called mobase.log / mobase.LogLevel which the Python
bindings do not expose, crashing .omod installs with AttributeError.
Route messages through stderr so the Python runner forwards them to
MOBase::log::error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
LOOT (and any other tool that edits the plugin list) writes to the
deployed copies in the Wine prefix AppData. afterRun was syncing
saves and INIs back but not plugins, so LOOT's reordering was
silently reverted by savePluginList() writing the old in-memory
order on top of the untouched profile file.
Add WinePrefix::syncPluginsBack that picks the newest case variant
of plugins.txt and loadorder.txt from the prefix and copies them
back to the profile. Run it in afterRun alongside the existing
save/INI sync. For FileTime-based games (Skyrim LE, FO3, FNV) the
loadorder.txt removal now happens after the sync, so the file-time
fallback still works.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
The auto-prompt in organizercore already offers to fix the registry
on launch, so the manual button is redundant.
BethINI Pie plugin compared against managedGame()->gameName(), but
GameFalloutNV returns "New Vegas" while BethINI's app folder is
"Fallout New Vegas" — add an alias map so NV is detected correctly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|