diff --git a/CreamInstaller/Forms/InstallForm.cs b/CreamInstaller/Forms/InstallForm.cs index 1fb20fe..2712a32 100644 --- a/CreamInstaller/Forms/InstallForm.cs +++ b/CreamInstaller/Forms/InstallForm.cs @@ -381,7 +381,10 @@ internal sealed partial class InstallForm : CustomForm UseProxy = selection.UseProxy, ProxyDllName = selection.UseProxy ? selection.Proxy ?? Selection.DefaultProxy : null, UseExtraProtection = selection.UseExtraProtection, - Dlc = selection.DLC.Select(dlc => new InstalledDlcRecord + Dlc = selection.DLC + .GroupBy(dlc => dlc.Id) + .Select(g => g.First()) + .Select(dlc => new InstalledDlcRecord { DlcType = dlc.Type.ToString(), Id = dlc.Id, diff --git a/CreamInstaller/Forms/MainForm.cs b/CreamInstaller/Forms/MainForm.cs index 2ae30eb..85537af 100644 --- a/CreamInstaller/Forms/MainForm.cs +++ b/CreamInstaller/Forms/MainForm.cs @@ -1158,10 +1158,12 @@ internal sealed partial class MainForm : CustomForm if (selection.TreeNode.TreeView is null) _ = selectionTreeView.Nodes.Add(selection.TreeNode); - // Restore DLC children from saved record + // Restore DLC children from saved record, deduplicating by ID if (record.Dlc != null && record.Dlc.Count > 0) { - foreach (InstalledDlcRecord dlcRecord in record.Dlc) + foreach (InstalledDlcRecord dlcRecord in record.Dlc + .GroupBy(d => d.Id) + .Select(g => g.First())) { if (!Enum.TryParse(dlcRecord.DlcType, out DLCType dlcType)) continue; @@ -1476,7 +1478,10 @@ internal sealed partial class MainForm : CustomForm UseProxy = existing?.UseProxy ?? false, ProxyDllName = existing?.UseProxy == true ? existing.ProxyDllName : null, UseExtraProtection = existing?.UseExtraProtection ?? false, - Dlc = selection.DLC.Select(dlc => new InstalledDlcRecord + Dlc = selection.DLC + .GroupBy(dlc => dlc.Id) + .Select(g => g.First()) + .Select(dlc => new InstalledDlcRecord { DlcType = dlc.Type.ToString(), Id = dlc.Id, diff --git a/CreamInstaller/SelectionDLC.cs b/CreamInstaller/SelectionDLC.cs index e5382e0..3258625 100644 --- a/CreamInstaller/SelectionDLC.cs +++ b/CreamInstaller/SelectionDLC.cs @@ -71,7 +71,20 @@ internal sealed class SelectionDLC : IEquatable Type == other.Type && GameId == other.GameId && Id == other.Id); internal static SelectionDLC GetOrCreate(DLCType type, string gameId, string id, string name) - => FromId(type, gameId, id) ?? new SelectionDLC(type, gameId, id, name); + { + // For Steam DLCs, Steam and SteamHidden represent the same DLC discovered + // through different code paths. Look up by (gameId, id) ignoring the Steam + // subtype to prevent duplicate entries for the same DLC. + if (type is DLCType.Steam or DLCType.SteamHidden) + { + SelectionDLC existing = All.Keys.FirstOrDefault( + dlc => dlc.GameId == gameId && dlc.Id == id + && dlc.Type is DLCType.Steam or DLCType.SteamHidden); + if (existing is not null) + return existing; + } + return FromId(type, gameId, id) ?? new SelectionDLC(type, gameId, id, name); + } internal static SelectionDLC FromId(DLCType type, string gameId, string dlcId) => All.Keys.FirstOrDefault(dlc => dlc.Type == type && dlc.GameId == gameId && dlc.Id == dlcId);