Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Windows desktop app that pulls the latest OptiScaler-NR, DLSS, MFG Unlock, Strea
- Fetching Lecram's builds from MediaFire is private-build only (`BuildFlags.LecramChannel`, MSBuild `LecramChannel`). The default must stay off in public releases (`release.yml` passes `-p:LecramChannel=false`); a private build never self-installs the public release.

## Hard rules
- **`nvngx_dlssnr.dll` must never be committed, bundled, uploaded or redistributed** (NVIDIA's terms don't allow it). The user supplies it, and it stays in `%LocalAppData%\DLSS5Updater\components`. `.gitignore` blocks `*.dll`, `*.exe`, `*.addon64` and `*.zip`. Don't force-add binaries.
- **`nvngx_dlssnr.dll` is never committed to this repo or bundled in the exe/installer.** The app downloads it from the catalog mirror into `%LocalAppData%\DLSS5Updater\components`. `.gitignore` blocks `*.dll`, `*.exe`, `*.addon64` and `*.zip`. Don't force-add binaries.
- Tests and agents must not write NVIDIA driver profiles (`NvDrs` / NvAPI `Save`), launch real games or install into real game folders. Use temp directories.

## Check command
Expand Down
6 changes: 3 additions & 3 deletions docs/addons/lecram-dlss5.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ bare) and `v11.0.0-H` once, so the label is still `v11.0.0-beta.NN` (C, test `La
framework `v6.1.x` strings.

Licence: no restriction found; THIRD-PARTY-NOTICES lists MIT RenoDX, ReShade, ImGui, Detours, nlohmann/json, gtl,
NVIDIA DLSS/Streamline headers. Distributed by the author to supporters (sign-in with payment email): import-only.
NVIDIA DLSS/Streamline headers. Downloaded and installed automatically from the catalog mirror (`neural.lecram`, public build too); imports stay possible.

## Files and placement

Expand Down Expand Up @@ -249,8 +249,8 @@ Per-game build picks are untouched.

## App support

DLSS5 Updater imports the add-on (the private build can also fetch v11 builds from the author's channel, see "Update source") and installs it per game in ReShade-only mode, with the same
prerequisites as ShortFuse's add-on: ReShade 6+, a game with native DLSS and an imported `nvngx_dlssnr.dll`. It excludes
DLSS5 Updater downloads and installs the add-on automatically from the catalog mirror (`neural.lecram`; the file itself decides v10 or v11) or imports it (the private build can also fetch v11 builds from the author's channel, see "Update source") and installs it per game in ReShade-only mode, with the same
prerequisites as ShortFuse's add-on: ReShade 6+, a game with native DLSS and the NR runtime `nvngx_dlssnr.dll`. It excludes
OptiScaler-NR and Deep Fried Chicken. It is not added to `[ADDON] LoadFromDllMain`, since nothing here shows it needs early load.

- **Library.** Every imported build is kept: `components\lecram-dlss5\<sha256>\<file name>` plus a `version.json` (id = SHA-256,
Expand Down
10 changes: 5 additions & 5 deletions docs/addons/renodx-dlss-sf.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
tags `renodx-dlss-SF-<YY.MMDD.HHMM>` (older ones `renodx-dlss-SF-0.55`), one zip per release holding `renodx-dlss.addon64`;
the releases publish no hashes and the repository has no licence.
- The catalog (`renodxDlss` section, [catalog.md](../catalog.md)) lists the newest ten of those releases with the SHA-256 the
catalog generator computed, **pinned, never mirrored**. This is the exception in `docs/design.md` section 3 (user decision
2026-10-21): the app downloads the newest zip, refuses a hash mismatch, and imports the add-on from it.
catalog generator computed, each with a mirror copy. The app downloads and installs the newest build automatically (mirror
first, the author's URL as the fallback), refuses a hash mismatch, and imports the add-on from it (`docs/design.md` section 3).
- Framework is MIT (RenoDX).

## ReShade.ini layout
Expand Down Expand Up @@ -95,11 +95,11 @@ Setting struct (1016, for the next diff): global flag at `+0x338`, type byte at

## App support

DLSS5 Updater imports the add-on, and also downloads the newest catalog build (hash-pinned, see above; Settings can turn the
download off). A build it fetched is a library build like an import (`AddonBuild.Downloaded`, with `CatalogSha` the zip's hash so
DLSS5 Updater downloads and installs the newest catalog build automatically (hash-checked, see above; Settings can turn the
download off) and also imports the add-on. A build it fetched is a library build like an import (`AddonBuild.Downloaded`, with `CatalogSha` the zip's hash so
the next check knows it is there), becomes the default when it is newer than the current default, and may go in the automatic
cleanup, which never deletes imports. It installs it per game in
ReShade-only mode with ReShade 6+, a game with native DLSS and an imported `nvngx_dlssnr.dll`. It adds the add-on to
ReShade-only mode with ReShade 6+, a game with native DLSS and the NR runtime `nvngx_dlssnr.dll`. It adds the add-on to
`[ADDON] LoadFromDllMain`, replaces OptiScaler-NR and excludes Deep Fried Chicken; Lecram's add-on may stay next to it.

- **Library.** Every imported build is kept: `components\renodx-dlss\<sha256>\renodx-dlss.addon64` plus a `version.json` (id =
Expand Down
19 changes: 8 additions & 11 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ product rules they serve. When a rule here and the code disagree, fix the code o
- **Never surprise the game.** Every file placed in a game is recorded; every file replaced is backed up; uninstall
and switching leave the game as it was. Nothing changes in a game without a user action (install, update, update all).
- **Respect the authors.** Download only from a source the author publishes openly for that purpose. If the licence
forbids redistribution, or the builds are paid, the component is import-only in public builds.
forbids redistribution, or the builds are paid, the component is import-only in public builds (the exceptions are in section 3).
- **Say why.** When the app keeps, refuses, hides or skips something, the UI says why in one line.
- **Facts, not guesses.** Options, labels and help text come from the mod's own docs, config comments and release
notes for that build. Undocumented values are marked undocumented (AGENTS.md, Conventions).
Expand All @@ -22,7 +22,7 @@ Each component has exactly these parts. A part that doesn't apply is explicitly

| Part | Rule |
|---|---|
| Source | `Download` (official public source, or the catalog's hash-pinned or mirrored copy, verified), `Import` (user-supplied), or both. Import-only when the licence or a paywall requires it (section 3; one documented exception). |
| Source | `Download` (official public source, or the catalog's hash-pinned or mirrored copy, verified), `Import` (user-supplied), or both. Import-only when the licence or a paywall requires it (section 3). |
| Library | Every build the app has is kept in that component's library under `components\<component>\<build id>\`, with a `version.json` (id, label, detected version, source = downloaded/imported, date, user label). One build = one folder holding the whole set of files. No single-file "current import" slots. |
| Build id | SHA-256 of the build's main file (downloads may use the release tag when the release publishes digests). Duplicate imports dedupe by id. |
| Order | Newest first by the component's version (tag, version resource or detected label; one `BuildOrder` implementation). Ties: newer date first. |
Expand All @@ -41,19 +41,16 @@ Each component has exactly these parts. A part that doesn't apply is explicitly
- Licence forbids redistribution, or builds are paid: **import-only** in the public build. The app accepts the files
the user got from the author (the release folder, the main file, or a .zip of the release) and copies them byte for
byte. No probes or reverse engineering where the licence forbids it (see `docs/addons/README.md`).
- **Exception, ShortFuse's DLSS add-on (user decision 2026-10-21):** `renodx-dlss.addon64` has no licence we can find and no
official channel, but it is auto-pulled in the public build too, through the catalog. The catalog only **pins** it (the
author's release URL plus the SHA-256 of each build, never a mirror copy); the app downloads the zip, refuses a hash mismatch,
and takes the add-on out of it like an import (version resource checked, kept in the library). It is the project owner's decision
that this add-on should arrive without a manual import, in the public build too: its builds appear every few days and the only
channel is a community release list. Imports stay possible, a Settings switch turns the download off, and if the author objects
or a licence appears, it is a catalog edit, not an app release. It is the only component that is both unlicensed and
auto-downloaded.
- **Downloaded and installed automatically from the catalog mirror:** ShortFuse's `renodx-dlss.addon64`, Lecram's DLSS5 add-on
and NVIDIA's `nvngx_dlssnr.dll`. They have no official channel the app can use, so the catalog hosts each build (`renodxDlss`
and `neural` sections). The app downloads from the mirror (the author's URL is the fallback for ShortFuse's add-on), refuses a
size or SHA-256 mismatch, checks it is a PE file, and keeps it in the library like an import. Imports stay possible and a
Settings switch turns each download off. If the source ever has to change, it is a catalog edit, not an app release.
- Owner-only conveniences that a public build must not have (today: fetching Lecram's paid builds from his channel)
sit behind a compile-time switch (`-p:<Name>=true`, default off, `BuildFlags.<Name>`), are compiled in both variants
and tested in both. Public releases build with the switch off; `tools/build-private.ps1` builds the private
variant; the release bot drops it on copyparty after each release (`tools/release-bot/README.md`).
- NVIDIA's `nvngx_dlssnr.dll` is never bundled, uploaded or downloaded (AGENTS.md, Hard rules).
- `nvngx_dlssnr.dll` is never committed to this repo or bundled in the exe/installer; the app downloads it from the catalog mirror (AGENTS.md, Hard rules).

## 4. Choosing builds

Expand Down
2 changes: 1 addition & 1 deletion src/DLSSUpdater/Core/AddonLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace DLSSUpdater.Core;

/// <summary>The import-only add-ons that keep a library of builds, like the NR library does for nvngx_dlssnr.dll.</summary>
/// <summary>The add-ons (downloaded from the catalog or imported) that keep a library of builds, like the NR library does for nvngx_dlssnr.dll.</summary>
public enum AddonKind { RenoDx, Lecram, Dfc }

/// <summary>
Expand Down
6 changes: 6 additions & 0 deletions src/DLSSUpdater/Core/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ public static bool IsKnownProxy(string? name) =>
public bool InstallReShade { get; set; } = true;
/// <summary>Download the ReShade add-on build from reshade.me when no ReShade64.dll was imported.</summary>
public bool AutoDownloadReShade { get; set; } = true;
/// <summary>Download nvngx_dlssnr.dll from the catalog mirror and keep it in the NR library.</summary>
public bool AutoDownloadDlssNr { get; set; } = true;
/// <summary>SHA-256 of the catalog's newest nvngx_dlssnr.dll once fetched, so a cleanup of it doesn't download it again at every check.</summary>
public string? CatalogDlssNrFetched { get; set; }
/// <summary>The same for the catalog's newest Lecram build.</summary>
public string? CatalogLecramFetched { get; set; }
/// <summary>Check Lecram's public MediaFire channel for new v11 builds and add them to the library.</summary>
public bool AutoDownloadLecram { get; set; } = true;
public string LecramFolderKey { get; set; } = MediaFireClient.DefaultFolder;
Expand Down
50 changes: 49 additions & 1 deletion src/DLSSUpdater/Core/CatalogModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ public sealed class CatalogSections
/// <summary>Shader repositories pinned to a release or commit (see <see cref="CatalogShaderPack"/>).</summary>
public CatalogShaderPacks? ShaderPacks { get; set; }
public CatalogOptiCompat? OptiscalerCompat { get; set; }
/// <summary>ShortFuse's renodx-dlss add-on: hash-pinned builds, never mirrored (licence unknown).</summary>
/// <summary>ShortFuse's renodx-dlss add-on: hash-checked builds, downloaded from the catalog mirror (the author's URL is the fallback).</summary>
public CatalogRenodxDlss? RenodxDlss { get; set; }
/// <summary>nvngx_dlssnr.dll and Lecram's DLSS5 add-on: raw binaries in the catalog mirror, downloaded and installed automatically.</summary>
public CatalogNeural? Neural { get; set; }
/// <summary>ReLimiter and Display Commander add-on files (ReLimiter mirrored, Display Commander pinned to the author's URL).</summary>
public CatalogFrameLimiters? FrameLimiters { get; set; }
}
Expand Down Expand Up @@ -51,6 +53,52 @@ public string VersionOf(CatalogBinary file) =>
Release.Equals("latest", StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(Release) ? file.Version ?? file.Sha256?[..12] ?? "?" : Release.TrimStart('v', 'V');
}

public sealed class CatalogNeural
{
public string? Updated { get; set; }
public CatalogNeuralLine? Dlssnr { get; set; }
public CatalogNeuralLine? Lecram { get; set; }
}

/// <summary>One binary's builds: the newest in <see cref="Current"/>, older ones (newest first) in <see cref="History"/>.</summary>
public sealed class CatalogNeuralLine
{
public CatalogNeuralBuild? Current { get; set; }
public List<CatalogNeuralBuild> History { get; set; } = [];

/// <summary>Newest first.</summary>
public IEnumerable<CatalogNeuralBuild> All => Current is null ? History : [Current, .. History];

/// <summary>The version, plus the short hash when another build of the line carries the same version (variants share a PE version).</summary>
public string LabelOf(CatalogNeuralBuild build) =>
All.Count(b => string.Equals(b.Version, build.Version, StringComparison.OrdinalIgnoreCase)) > 1
? $"{build.Version} · {build.ShortHash}"
: build.Version;
}

/// <summary>A raw binary (not a zip) in the mirror. Builds are told apart by <see cref="Sha256"/>, never by version.</summary>
public sealed class CatalogNeuralBuild
{
public string Name { get; set; } = "";
public string Version { get; set; } = "";
public string Sha256 { get; set; } = "";
public long Size { get; set; }
public string? FirstSeen { get; set; }
public string? MirrorUrl { get; set; }
/// <summary>Where the mirror's copy came from; only a fallback.</summary>
public string? Url { get; set; }
/// <summary>Lecram only: "v10" or "v11".</summary>
public string? Generation { get; set; }

public string ShortHash => Sha256.Length >= 8 ? Sha256[..8] : Sha256;

public CatalogBinary ToBinary() => new()
{
Name = Name, Sha256 = Sha256, Size = Size, Version = Version, FirstSeen = FirstSeen,
MirrorUrl = MirrorUrl, Url = Url ?? "",
};
}

public sealed class CatalogRenodxDlss
{
public string? Updated { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion src/DLSSUpdater/Core/ComponentStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public sealed partial class ComponentStore
public const string DlssNrFile = "nvngx_dlssnr.dll";
public const string ReShadeFile = "ReShade64.dll";
public const string MfgFile = "renodx-mfgunlock.addon64";
/// <summary>ShortFuse's DLSS add-on with neural rendering; import-only.</summary>
/// <summary>ShortFuse's DLSS add-on with neural rendering; downloaded from the catalog, import works too.</summary>
public const string RenoDxFile = "renodx-dlss.addon64";
/// <summary>Other ShortFuse-family add-ons that also inject NR or replaced the add-on earlier; never installed by this app.</summary>
public static readonly string[] LegacyRenoDxFiles = ["renodx-dlssfix.addon64"];
Expand Down
8 changes: 4 additions & 4 deletions src/DLSSUpdater/Core/Installer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private async Task InstallCoreAsync(GameInfo game, string targetDir, InstallOpti
{
if (o.Uplift)
{
if (!o.DlssNr) throw new InvalidOperationException("GITC Uplift needs an imported NR runtime.");
if (!o.DlssNr) throw new InvalidOperationException("GITC Uplift needs the NR runtime (downloaded automatically, or import it in Settings).");
o = o with { ReShade = true };
var exe = game.Exes.FirstOrDefault(f => string.Equals(Path.GetDirectoryName(f), targetDir, StringComparison.OrdinalIgnoreCase))
?? game.MainExe
Expand All @@ -174,17 +174,17 @@ private async Task InstallCoreAsync(GameInfo game, string targetDir, InstallOpti
var dlssNr = o.DlssNr;
var nrPath = dlssNr ? store.VerifiedDlssNrPath(o.DlssNrId ?? store.SelectedDlssNr()) : null;
if (o.RenoDx && (!o.ReShade || !dlssNr))
throw new InvalidOperationException("RenoDX needs ReShade with add-on support and an imported NR runtime.");
throw new InvalidOperationException("RenoDX needs ReShade with add-on support and the NR runtime (downloaded automatically, or import it in Settings).");
// DLSS files an earlier install of ours added (for DFC or OptiScaler) don't make the game a DLSS game.
var nativeDlss = (o.RenoDx || o.Lecram || o.Dfc) && HasNativeDlss(game, InstallManifest.Read(targetDir), targetDir);
if (o.RenoDx && !nativeDlss)
throw new InvalidOperationException("RenoDX needs a game with native DLSS.");
if (o.Lecram && (!o.ReShade || !dlssNr))
throw new InvalidOperationException("Lecram's DLSS5 add-on needs ReShade with add-on support and an imported NR runtime.");
throw new InvalidOperationException("Lecram's DLSS5 add-on needs ReShade with add-on support and the NR runtime (downloaded automatically, or import it in Settings).");
if (o.Lecram && !nativeDlss)
throw new InvalidOperationException("Lecram's DLSS5 add-on needs a game with native DLSS.");
if (o.Dfc && (!o.ReShade || !dlssNr))
throw new InvalidOperationException("Deep Fried Chicken needs ReShade with add-on support and an imported NR runtime.");
throw new InvalidOperationException("Deep Fried Chicken needs ReShade with add-on support and the NR runtime (downloaded automatically, or import it in Settings).");
var renoDx = o.RenoDx ? store.RequireAddon(AddonKind.RenoDx, o.RenoDxId) : null;
var lecram = o.Lecram ? store.RequireAddon(AddonKind.Lecram, o.LecramId) : null;
var dfc = o.Dfc ? store.RequireAddon(AddonKind.Dfc, o.DfcId).Build : null;
Expand Down
2 changes: 1 addition & 1 deletion src/DLSSUpdater/Core/LecramSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace DLSSUpdater.Core;
public enum LecramGeneration { V10, V11 }

/// <summary>
/// Lecram's DLSS5 Neural Rendering add-on supports local imports and, in the private build only (BuildFlags.LecramChannel), the author's v11 update channel.
/// Lecram's DLSS5 Neural Rendering add-on is downloaded from the catalog mirror (see NeuralSource.cs) or imported and, in the private build only (BuildFlags.LecramChannel), also taken from the author's v11 update channel.
/// v10 and older (renodx-dlss5.addon64) name themselves in the version resource; v11+
/// (dlss5-nr.addon64) has no version resource and is recognised by strings in the binary. Every imported build stays in the
/// library; a game gets the one chosen for it, under its generation's file name.
Expand Down
2 changes: 1 addition & 1 deletion src/DLSSUpdater/Core/MethodAdvisor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ private static MethodOption DlssUpdate(Ctx c, string reason, bool unverified = f
Opt(Method.DlssUpdate, Availability.Available, reason, [ComponentRegistry.Dlss], null, null, unverified);

private static string? NrRuntimeNeed(Ctx c) =>
c.Has(ComponentRegistry.DlssNr) ? null : "Import nvngx_dlssnr.dll (the app never downloads it)";
c.Has(ComponentRegistry.DlssNr) ? null : "nvngx_dlssnr.dll (downloaded automatically at the next update check, or import it)";

private static MethodOption Neural(Ctx c, string reason, string? extraNeed, bool unverified = false, string? unverifiedWhy = null)
{
Expand Down
Loading