Drops OptiScaler v0.9.1 + a FH5-tuned OptiScaler.ini into the FH5
install dir to unlock FSR 4 INT8 on this RDNA 3 (Navi 32) box.
OptiScaler intercepts FH5's DLSS/XeSS calls and reroutes them through
the bundled FFX SDK. Per the OptiScaler FH5 wiki page: rename
OptiScaler.dll to dxgi.dll, set Dxgi=false, DlssReactiveMaskBias=0.65,
and Fsr4Update=true for the INT8 RDNA 3 path.
Sets Steam launch options PROTON_FSR4_UPGRADE=1 and
DXIL_SPIRV_CONFIG=wmma_rdna3_workaround on fh5-optiscaler (the FSR 4
wiki documents both as required for RDNA 3 on Linux).
fh5-vkd3d-no-hvv is its own mod (no files, just one launchOptions
entry for VKD3D_CONFIG=no_upload_hvv) so the upload-hvv workaround
can be removed when a future Proton release fixes the underlying
issue without disturbing the OptiScaler config.
Extends the intro skip stub to cover the hires variant of the
T10/Microsoft Studios splash; the engine picks SD or hires based on
the installed asset profile, so stub both per PCGamingWiki.
stdenvNoCC + p7zip extraction; strips installer scripts and README,
keeps Licenses/. dontFixup since the artifacts are Windows DLLs.
meta.license is unfreeRedistributable to reflect the bundled XeSS
(Intel SLA) alongside the GPL-3.0 source.
Wires lib/overlays.nix into mkDesktopHost (was muffin-only) and adds
"optiscaler" to the unfree allowlist on jovian hosts so yarn can
consume it without flipping the global allowUnfree flag.
Three additions on top of the file-replacement scaffolding:
- mode = "init": create-on-first-apply, leave-alone-otherwise. For
files the application writes back to (configs edited in-game, save
files). Operator pushes a new template by deleting the target.
- chmod 644 after every copy. shutil.copy2 preserved the source's
/nix/store mode (0o444), which made dropped DLL configs read-only.
Apps that wrote back (OptiScaler "Save INI") got EACCES, which in
OptiScaler's case cascaded into CreateSwapChainForHwnd returning
E_FAIL and crashed FH5 on launch.
- launchOptions = listOf str. Multiple mods targeting the same
steamAppId have their lists concatenated (mod-name alphabetical),
joined with spaces, %command% appended once. Written into Steam's
per-app block in userdata/<id>/config/localconfig.vdf via vdf
parse + atomic os.replace. Idempotent.
- X-ConfigHash on the systemd unit so switch-to-configuration switch
re-runs apply when the manifest changes.
The previous fix used canonical Off (mode 0x05) everywhere we wanted the
trigger to feel released \u2014 pre-race per-frame, idle timeout, shutdown.
Per Sony's docs (Nielk1 Rev 6) mode 0x05 "actively returns the trigger
stop to the neutral position". Re-asserting it 60 times/sec from main
thread, propagated by pydualsense's BG thread to the controller at
~250 Hz, made the trigger motor audibly whine as the firmware repeatedly
snapped the (already-neutral) trigger back to neutral.
Right answer: hybrid. One-shot 0x05 on the in-race \u2192 not-in-race
transition (and on the telemetry-idle timeout) so the firmware actually
retracts the motor; mode 0x00 (TriggerModes.Off, no-op clear) for
steady-state pre-race / idle frames so we're not yelling RESET in the
firmware's ear forever.
Implementation: prev_in_race tracks the last frame's race state. Steady
non-race frames call _apply_normal (mode 0x00); the first frame after a
race-end transition calls _apply_off (mode 0x05). pydualsense's BG
thread holds the 0x05 in memory long enough (one main-thread frame =
~16ms = ~4 BG iterations) to publish it to the controller before main
switches the in-memory state to 0x00.
Restores _apply_normal and DS_MODE_NORMAL that the previous commit
deleted. Updates divergence #4 in the module docstring.
Two issues in the deployed daemon:
1. After FH5 exits, the lightbar stayed lit. reset_triggers() touched
only triggers; pydualsense's BG sendReport thread kept re-publishing
whatever TouchpadColor we last set, so the controller stayed in the
last race color forever.
2. R2 had residual tension in FH5's main menu and on the desktop after
a race. Pre-race / idle states were emitting RacingDSX's NormalTrigger
(mode byte 0x00), which per Sony's docs (Nielk1 Rev6) only clears
state without retracting the trigger motor; mode 0x05 (canonical Off
/ Reset) actively returns the trigger to neutral. RacingDSX-on-Windows
gets away with 0x00 because something else (Steam Input or the OS)
reliably resets the motor on focus loss; on Linux nothing does.
Fixes:
- Drop _apply_normal/DS_MODE_NORMAL. Use _apply_off (mode 0x05) for every
'release the trigger' intent: pre-race per-frame, idle timeout, mid-race
zero-strength fallback, shutdown.
- Add reset_lightbar() that writes RGB(0,0,0).
- Track have_telemetry and fire the idle-timeout branch whenever
telemetry has been silent for IDLE_TIMEOUT_S, regardless of in_race.
Reset both triggers and lightbar in that branch.
Documented as divergence #4 in the module docstring.
BIOS 2423→4101 update on yarn required an fTPM reset, which broke the
sealed age identity at /var/lib/agenix/tpm-identity. Bootstrapped a new
identity against the new SRK and rotated yarn's recipient.
age-plugin-tpm 1.0+ emits age1tag1… (p256tag) recipients by default and
refuses to encrypt to legacy age1tpm1… ones, so rotated mreow's recipient
to the same encoding (same key, new bech32 HRP) and added an
age-plugin-tag→age-plugin-tpm symlink in the rage wrapper so rage's
plugin dispatch finds the binary under the new prefix. Stripped the
trailing host labels from the tpm recipient strings — rage's stricter
bech32 parser now rejects the trailing whitespace; labels live in
adjacent Nix comments instead.
oo7-server 0.6.0 only feeds the systemd / PAM secret to existing
keyrings discovered on disk. On first run no keyring exists yet, the
daemon creates an empty 'Login' collection via LockedKeyring::open,
the credential is silently ignored, and any client Unlock() routes to
a prompt that nothing on a niri desktop can satisfy.
Patches/oo7-server/0001-... is upstream commit cf7b9a9 (PR #443)
regenerated relative to the package's sourceRoot ('server/'). It
switches the auto-created default-keyring path to UnlockedKeyring::open
when a secret is available.
The override threads the patch through pkgs.oo7-server.overrideAttrs
in modules/desktop-oo7-daemon.nix and uses the patched derivation for
both services.dbus.packages and systemd.packages so the user unit and
D-Bus activation file land from the same store path. Cargo.lock is
untouched, so the existing cargoDeps hash stays valid.
Drop the override once nixpkgs ships an oo7-server release that
includes the fix (anything past 0.6.0).
oo7-daemon was running but its 'Login' keyring stayed locked because
nothing supplied a master password, so libsecret clients (flare in
particular) blocked indefinitely on keyring.unlock().
The upstream user unit declares
ImportCredential=oo7.keyring-encryption-password
which picks up matching credentials from systemd's per-service
credential machinery. Wire LoadCredential=oo7.keyring-encryption-password
to the agenix-decrypted secret so the daemon unlocks at session start
without any prompt.
The password itself is a fresh 64-byte urandom value encrypted to all
desktop recipients (admin SSH key + mreow + yarn TPM identities); it's
opaque to the user and never typed manually. Owner is primary so the
user-scope unit's LoadCredential read works without elevating.
Verified the activation script chowns the decrypted file primary:users
mode 0400, the user unit override carries the LoadCredential line, and
the resulting drv builds clean.
Without a secret-service implementation on the bus, libsecret clients
like flare fail at startup with 'The communication with libsecret
failed'. None of the desktop hosts had one wired up.
oo7-daemon is the matching pure-Rust implementation (same project as
the oo7 crate flare uses internally), without the GNOME plumbing that
gnome-keyring would drag in. Register the package's D-Bus service
file and systemd user unit, start the daemon at user login, and alias
the unit as dbus-org.freedesktop.secrets.service so D-Bus
auto-activation also resolves cleanly when the wantedBy start hasn't
fired yet.
Verified the toplevel build and that the resulting system carries the
oo7-daemon user unit, the dbus alias symlink, and the
default.target.wants entry.
- patches/flare/000{1..5}-*.patch: typing indicators, formatted
messages, edited messages, multi-select with delete-for-me, and
in-channel message search. Mirror the matching commits in
~/projects/forks/flare and apply cleanly on top of upstream 0.20.4
(which is what nixpkgs ships).
- home/profiles/gui.nix: include a flare-signal override that appends
the patches via overrideAttrs. None of them touch Cargo.lock so the
cargoDeps hash stays valid; signal-desktop stays alongside it.
agenix activation runs from initrd-nixos-activation-start, which fires
right after /sysroot/persistent is mounted but before impermanence's
stage-2 bind mounts. The TPM identity at /var/lib/agenix/tpm-identity
was therefore unreadable at activation time, and every secret silently
failed to decrypt: 'no readable identities found'. Visible downstream
fallout was pull-update-apply hitting HTTP 401 against the binary cache
because nix-cache-netrc was never written to /run/agenix.
Mark /var/lib/agenix as neededForBoot via a bare fileSystems entry,
mirroring the existing /home/${username} bind. Drop the now-redundant
environment.persistence directory entry to avoid two competing units.
`bun2nix.hook` (used by upstream omp's package.nix) sets
patchPhase = bunPatchPhase
at the end of its setup-hook unless `dontUseBunPatch` is already set.
`bunPatchPhase` only runs `patchShebangs` plus a HOME mktemp; it never
iterates over `$patches`. The standard nixpkgs `patches` attribute
therefore went into the derivation env but was silently ignored at
build time, leaving the deployed omp binary unpatched.
Switch to applying the two patches via `prePatch` (which `bunPatchPhase`
does call). Verified with strings(1) over the rebuilt binary that both
patch hunks land:
/wrong_api_format|...|invalid tool parameters/ (patch 0001)
stubsReasoningContent ... thinkingFormat == "openrouter" (patch 0002)