feat(play): Windows' graphics preference and the NVIDIA profile follow the player into a new build #87

Merged
HumanBean merged 1 commit from dyst/LongshotLauncher:feat/driver-settings-follow into main 2026-11-15 08:13:59 +00:00
Member

After an update into a new folder, the game no longer runs on the GPU the player chose for it in Windows, and the NVIDIA app's settings for it (Smooth Motion, DLSS overrides) stop applying (Longshot issue 224). Windows and the driver keep those by the program's full path, which a new folder changes. This brings them over before Play.

Builds on #84 (merged): rebased onto main after it, one commit.

What changed

  • Windows' graphics preference (Core/DriverSettings.cs GpuPreference): the per-program GPU choice under Settings > System > Display > Graphics is a value of HKCU\Software\Microsoft\DirectX\UserGpuPreferences, named by the exe's path. A new build's exe with no value gets the one from the most recently updated other build that has one. This goes through the existing IUserRegistry, current user only, no admin.
  • NVIDIA program profile (DriverSettings.Nvidia, NvApiProfiles):
    • What it does: if no driver profile names the new exe (by its path or its file name), but one names an old build's exe by its path, the new exe is added to that same profile. Every setting in the profile then applies, whatever it is, so the launcher never needs to know Smooth Motion's or any other setting's ID.
    • How: NVAPI's driver settings in nvapi64.dll (NvAPI_DRS_CreateSession, LoadSettings, FindApplicationByName, GetProfileInfo, CreateApplication, SaveSettings). The IDs and structure layouts come from NVIDIA's open nvapi headers (NVDRS_APPLICATION_V4, NVDRS_PROFILE_V1).
    • Where no NVIDIA driver exists: nothing happens.
  • Before Play (LauncherService.CarryDriverSettings, Windows only):
    • Sources: the other builds' game exes, most recently updated first, three at most, since each NVIDIA lookup loads the driver's settings.
    • Never destructive: nothing is ever taken away, and an exe that already has its own entry is left alone.
    • A refusal changes nothing: the game starts as before, and nothing is said.
    • Success notices: one line each on the home. These are new texts, so the other languages show them in English for now.
  • Docs: README design decisions.

Testing

Tested (Windows 11, RTX 3080, NVIDIA driver 621.14, not elevated):

  • python -I tests/test_launcher_core.py --strict: 1071 checks pass, after the rebase onto main (9254499). That includes the new DriverSettingsChecks:
    • Graphics preference: with none at all, nothing is written; the newest build's value is taken; a program's own value is kept; a program is never its own source.
    • NVIDIA profile: with no profile, nothing is added; a path-named profile is joined; a covered program is left alone; a profile that names the file name already covers a new copy.
    • Real driver, read only: where an NVIDIA driver is, it's read through NVAPI. On this PC, the driver's built-in Notepad profile is found and a made-up path is not, which checks the structure layouts.
  • dotnet build App -c Release: 0 warnings, 0 errors.
  • A separate read-only probe on this PC: session, load and find all work without elevation (NVAPI_OK). The IDs for CreateApplication and SaveSettings resolve in this driver. Neither was called.

Not tested:

  • The writes: CreateApplication and SaveSettings against a real driver. This PC has no profile naming a Longshot exe, and I didn't want to change the driver's settings without agreement.
  • The window and a real Play.

Must be tested:

  • Windows, NVIDIA, the NVIDIA app:
    1. Turn on a program setting for a launcher build's bin\longshot.exe, such as Smooth Motion.
    2. Update the build into a new folder with a launcher built from this branch, then press Play.
    3. Expect the new exe to show in the same program profile in the NVIDIA app, with the setting on, and the notice on the home once.
  • Windows, two GPUs:
    1. Set the old build's exe to the other GPU in Settings > Display > Graphics.
    2. Update and Play.
    3. Expect the new exe listed there with the same GPU.

For discussion

  • Does NvAPI_DRS_SaveSettings need an elevated process on current drivers? Reading works without it here. If saving is refused without admin (NVAPI_INVALID_USER_PRIVILEGE), this PR leaves things as they were and says nothing. The options are to keep it that way, to ask once per update behind an elevation prompt, or to leave NVIDIA out.
  • Should there be a launcher setting to turn the driver part off? It only ever adds entries, so I left one out for now.

Risks

  • Windows' registry: UserGpuPreferences gets a value for each new build's exe, copied as it was; old builds' values stay.
  • NVIDIA: the new exe is added to a profile the player made for an old one. Every setting in that profile then also applies to the new build, which is the intent. Removing it is done in the NVIDIA app, as for any program.
  • Turning it off: revert the commit.

Related: #57 (an update in place, which would keep the path and make this unneeded for updates), Longshot #729, #84, Longshot #736 (the GPU device row saved by card).

See #90 (NVIDIA app settings lost when the folder name changes).

🤖 Generated with Claude Code

After an update into a new folder, the game no longer runs on the GPU the player chose for it in Windows, and the NVIDIA app's settings for it (Smooth Motion, DLSS overrides) stop applying ([Longshot issue 224](https://git.magicbean.dev/MagicBeanDev/Longshot/issues/224)). Windows and the driver keep those by the program's full path, which a new folder changes. This brings them over before Play. Builds on #84 (merged): rebased onto `main` after it, one commit. ## What changed - **Windows' graphics preference** (`Core/DriverSettings.cs` `GpuPreference`): the per-program GPU choice under Settings > System > Display > Graphics is a value of `HKCU\Software\Microsoft\DirectX\UserGpuPreferences`, named by the exe's path. A new build's exe with no value gets the one from the most recently updated other build that has one. This goes through the existing `IUserRegistry`, current user only, no admin. - **NVIDIA program profile** (`DriverSettings.Nvidia`, `NvApiProfiles`): - **What it does:** if no driver profile names the new exe (by its path or its file name), but one names an old build's exe by its path, the new exe is added to that same profile. Every setting in the profile then applies, whatever it is, so the launcher never needs to know Smooth Motion's or any other setting's ID. - **How:** NVAPI's driver settings in `nvapi64.dll` (NvAPI_DRS_CreateSession, LoadSettings, FindApplicationByName, GetProfileInfo, CreateApplication, SaveSettings). The IDs and structure layouts come from NVIDIA's open nvapi headers (`NVDRS_APPLICATION_V4`, `NVDRS_PROFILE_V1`). - **Where no NVIDIA driver exists:** nothing happens. - **Before Play** (`LauncherService.CarryDriverSettings`, Windows only): - **Sources:** the other builds' game exes, most recently updated first, three at most, since each NVIDIA lookup loads the driver's settings. - **Never destructive:** nothing is ever taken away, and an exe that already has its own entry is left alone. - **A refusal changes nothing:** the game starts as before, and nothing is said. - **Success notices:** one line each on the home. These are new texts, so the other languages show them in English for now. - **Docs:** README design decisions. ## Testing **Tested** (Windows 11, RTX 3080, NVIDIA driver 621.14, not elevated): - `python -I tests/test_launcher_core.py --strict`: 1071 checks pass, after the rebase onto `main` (9254499). That includes the new `DriverSettingsChecks`: - **Graphics preference:** with none at all, nothing is written; the newest build's value is taken; a program's own value is kept; a program is never its own source. - **NVIDIA profile:** with no profile, nothing is added; a path-named profile is joined; a covered program is left alone; a profile that names the file name already covers a new copy. - **Real driver, read only:** where an NVIDIA driver is, it's read through NVAPI. On this PC, the driver's built-in Notepad profile is found and a made-up path is not, which checks the structure layouts. - `dotnet build App -c Release`: 0 warnings, 0 errors. - **A separate read-only probe on this PC:** session, load and find all work without elevation (`NVAPI_OK`). The IDs for `CreateApplication` and `SaveSettings` resolve in this driver. Neither was called. **Not tested:** - **The writes:** `CreateApplication` and `SaveSettings` against a real driver. This PC has no profile naming a Longshot exe, and I didn't want to change the driver's settings without agreement. - **The window and a real Play.** **Must be tested:** - **Windows, NVIDIA, the NVIDIA app:** 1. Turn on a program setting for a launcher build's `bin\longshot.exe`, such as Smooth Motion. 2. Update the build into a new folder with a launcher built from this branch, then press Play. 3. Expect the new exe to show in the same program profile in the NVIDIA app, with the setting on, and the notice on the home once. - **Windows, two GPUs:** 1. Set the old build's exe to the other GPU in Settings > Display > Graphics. 2. Update and Play. 3. Expect the new exe listed there with the same GPU. ## For discussion - **Does `NvAPI_DRS_SaveSettings` need an elevated process on current drivers?** Reading works without it here. If saving is refused without admin (`NVAPI_INVALID_USER_PRIVILEGE`), this PR leaves things as they were and says nothing. The options are to keep it that way, to ask once per update behind an elevation prompt, or to leave NVIDIA out. - **Should there be a launcher setting to turn the driver part off?** It only ever adds entries, so I left one out for now. ## Risks - **Windows' registry:** `UserGpuPreferences` gets a value for each new build's exe, copied as it was; old builds' values stay. - **NVIDIA:** the new exe is added to a profile the player made for an old one. Every setting in that profile then also applies to the new build, which is the intent. Removing it is done in the NVIDIA app, as for any program. - **Turning it off:** revert the commit. Related: #57 (an update in place, which would keep the path and make this unneeded for updates), Longshot #729, #84, Longshot #736 (the GPU device row saved by card). See #90 (NVIDIA app settings lost when the folder name changes). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(play): the game settings follow the player into a new build, and Linux builds get --user
All checks were successful
CI / Compile and test (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 6s
0f21cd92ee
An update into a new folder started the game from the default settings: its longshot_options.ini held only
make_game.py's compile_shaders=. Longshot's #729 keeps the settings in the user folder the launcher gives
with --user; this brings the settings to a build that has none and gives that folder on Linux too.

- GamePlay.UserFolder: the shared user folder on both systems (on Linux not while the build's folder has a
  user/ of its own, which the game takes in itself or keeps as the player's link); StartInfo passes it on
  Linux too
- SettingsCarry.Fill, before Play (LauncherService.CarrySettings): a build whose file has no setting of the
  player's is filled from the newest of the user folder's and the other builds' files, its compile_shaders=
  kept; the user folder's own file is never written, and a failure never stops the game from starting
- the Hookshot settings import writes into the file the build reads (OptionsFileOf: the user folder's once
  there is one); language.txt stays the build's
- BuildFolders: the folders GatherSaves looked in, shared with the settings
- tests: SettingsCarryChecks; the --user checks now expect it on Linux
feat(play): Windows' graphics preference and the NVIDIA profile follow the player into a new build
Some checks failed
CI / Compile and test (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Has been cancelled
9a06e6597e
Windows and NVIDIA's driver keep a program's own settings by its full path, and an update into a new folder
changes it: the GPU the player chose for the game in Windows, and the NVIDIA app's program settings (Smooth
Motion, Longshot issue 224), stopped applying after every update.

- Core/DriverSettings.cs: GpuPreference gives a new build's program the graphics preference
  (HKCU\Software\Microsoft\DirectX\UserGpuPreferences) of the most recently updated other build that has
  one; Nvidia adds it to the NVIDIA profile that names an old build's program by its path, so every setting
  in that profile applies. A program with its own entry is left alone, and nothing is taken away
- NvApiProfiles: INvidiaProfiles through nvapi64.dll's driver settings (NvAPI_DRS_*), the ids and layouts
  of NVIDIA's open nvapi headers
- LauncherService.CarryDriverSettings, before Play on Windows; the driver refusing (an elevation it may
  need) leaves things as they were and the game starts
- tests: DriverSettingsChecks with a fake registry and a fake driver, and NVAPI read for real where an
  NVIDIA driver is (nothing written)

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
dyst force-pushed feat/driver-settings-follow from 9a06e6597e
Some checks failed
CI / Compile and test (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Has been cancelled
to 3907351acd
All checks were successful
CI / Compile and test (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
2026-11-15 08:08:09 +00:00
Compare
HumanBean changed title from WIP: feat(play): Windows' graphics preference and the NVIDIA profile follow the player into a new build to feat(play): Windows' graphics preference and the NVIDIA profile follow the player into a new build 2026-11-15 08:13:44 +00:00
HumanBean deleted branch feat/driver-settings-follow 2026-11-15 08:14:00 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/LongshotLauncher!87
No description provided.