diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-14 02:45:12 -0600 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-14 02:45:25 -0600 |
| commit | 817e8f5cd26739c69d930d21cd9dc4c0b6e4984e (patch) | |
| tree | 52aed11d6751bb7d20b06acf197d56fac113203d /libs/nak/src/runtime_wrap.rs | |
| parent | 51a9f8f197727f00896e5de44569b098923527dd (diff) | |
Add FUSE external mapping support, BG3/Oblivion Remastered fixes, fomod-plus and NaK integration
FUSE VFS now deploys non-data-dir mod mappings (Paks, OBSE, UE4SS, etc.)
via real symlinks and injects file-level data-dir mappings (plugins.txt,
loadorder.txt) into the VFS tree. Fixes game launches for Oblivion
Remastered (Root Builder path resolution, script extender support) and
BG3 (Wine prefix documents directory, file mapper symlinks on Linux).
Vendors mo2-fomod-plus plugin and NaK crate for FOMOD installer and
game finder/runtime support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'libs/nak/src/runtime_wrap.rs')
| -rw-r--r-- | libs/nak/src/runtime_wrap.rs | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/libs/nak/src/runtime_wrap.rs b/libs/nak/src/runtime_wrap.rs new file mode 100644 index 0000000..d33bd59 --- /dev/null +++ b/libs/nak/src/runtime_wrap.rs @@ -0,0 +1,121 @@ +use std::env; +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn env_flag(name: &str) -> bool { + matches!( + env::var(name) + .unwrap_or_default() + .trim() + .to_ascii_lowercase() + .as_str(), + "1" | "true" | "yes" | "on" + ) +} + +pub fn use_steam_run() -> bool { + env_flag("NAK_USE_STEAM_RUN") +} + +pub fn use_umu_for_prefix() -> bool { + env_flag("NAK_USE_UMU_FOR_PREFIX") +} + +pub fn prefer_system_umu() -> bool { + env_flag("NAK_PREFER_SYSTEM_UMU") +} + +fn find_in_path(binary: &str) -> Option<PathBuf> { + let path = env::var_os("PATH")?; + env::split_paths(&path) + .map(|entry| entry.join(binary)) + .find(|candidate| candidate.exists()) +} + +pub fn resolve_umu_run() -> Option<PathBuf> { + if is_flatpak() { + // In Flatpak, umu-run must run on the host via flatpak-spawn --host. + let host_copy = env::var("XDG_DATA_HOME") + .ok() + .map(PathBuf::from) + .unwrap_or_else(|| { + let home = env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); + PathBuf::from(home).join(".local/share") + }) + .join("fluorine/umu-run"); + if host_copy.exists() { + return Some(host_copy); + } + // Fall back to bare name for host PATH resolution. + return Some(PathBuf::from("umu-run")); + } + + let bundled = env::var("NAK_BUNDLED_UMU_RUN") + .ok() + .map(PathBuf::from) + .filter(|p| p.exists()); + let system = find_in_path("umu-run"); + + if prefer_system_umu() { + system.or(bundled) + } else { + bundled.or(system) + } +} + +pub fn is_flatpak() -> bool { + Path::new("/.flatpak-info").exists() +} + +/// Build a command to run `exe` with the given environment variables. +/// +/// In Flatpak mode, `flatpak-spawn --host` is used and env vars are passed as +/// `--env=KEY=VALUE` flags (the host process does NOT inherit the sandbox env). +/// In steam-run mode, the command is wrapped with `steam-run`. +/// Otherwise the command runs directly. +pub fn build_command<S: AsRef<OsStr>>( + exe: impl AsRef<OsStr>, + envs: &[(&str, S)], +) -> Command { + if use_steam_run() { + let mut cmd = Command::new("steam-run"); + cmd.arg(exe.as_ref()); + for (key, value) in envs { + cmd.env(key, value.as_ref()); + } + return cmd; + } + if is_flatpak() { + let mut cmd = Command::new("flatpak-spawn"); + cmd.arg("--host"); + for (key, value) in envs { + cmd.arg(format!( + "--env={}={}", + key, + value.as_ref().to_string_lossy() + )); + } + cmd.arg(exe.as_ref()); + return cmd; + } + let mut cmd = Command::new(exe); + for (key, value) in envs { + cmd.env(key, value.as_ref()); + } + cmd +} + +/// Build a command with no extra environment variables. +pub fn command_for(exe: impl AsRef<OsStr>) -> Command { + build_command::<&str>(exe, &[]) +} + +pub fn bundled_umu_path_from_appdir(appdir: &Path) -> Option<PathBuf> { + let path = appdir.join("umu-run"); + if path.exists() { + Some(path) + } else { + None + } +} |
