diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj
index 4defe3c..0f30b9c 100644
--- a/CreamInstaller/CreamInstaller.csproj
+++ b/CreamInstaller/CreamInstaller.csproj
@@ -4,7 +4,7 @@
net7.0-windows
True
Resources\ini.ico
- 4.9.1
+ 4.9.2
2021, pointfeev (https://github.com/pointfeev)
CreamInstaller
Automatic DLC Unlocker Installer & Configuration Generator
diff --git a/CreamInstaller/Forms/InstallForm.cs b/CreamInstaller/Forms/InstallForm.cs
index e7264b1..43bbbb0 100644
--- a/CreamInstaller/Forms/InstallForm.cs
+++ b/CreamInstaller/Forms/InstallForm.cs
@@ -16,7 +16,7 @@ internal sealed partial class InstallForm : CustomForm
{
private readonly HashSet disabledSelections = new();
- private readonly int programCount = Selection.AllEnabled.Count;
+ private readonly int programCount = Selection.AllEnabled.Count();
private readonly bool uninstalling;
private int completeOperationsCount;
@@ -184,7 +184,7 @@ internal sealed partial class InstallForm : CustomForm
private async Task Operate()
{
- HashSet programSelections = Selection.AllEnabled;
+ HashSet programSelections = Selection.AllEnabled.ToHashSet();
operationsCount = programSelections.Count;
completeOperationsCount = 0;
foreach (Selection selection in programSelections)
@@ -205,7 +205,7 @@ internal sealed partial class InstallForm : CustomForm
++completeOperationsCount;
}
Program.Cleanup();
- HashSet failedSelections = Selection.AllEnabled;
+ HashSet failedSelections = Selection.AllEnabled.ToHashSet();
if (failedSelections.Count > 0)
if (failedSelections.Count == 1)
throw new CustomMessageException($"Operation failed for {failedSelections.First().Name}.");
diff --git a/CreamInstaller/Forms/SelectForm.Designer.cs b/CreamInstaller/Forms/SelectForm.Designer.cs
index bedda3b..4bf9a80 100644
--- a/CreamInstaller/Forms/SelectForm.Designer.cs
+++ b/CreamInstaller/Forms/SelectForm.Designer.cs
@@ -447,7 +447,7 @@ namespace CreamInstaller.Forms
private GroupBox programsGroupBox;
private ProgressBar progressBar;
private Label progressLabel;
- private CheckBox allCheckBox;
+ internal CheckBox allCheckBox;
private Button scanButton;
private Label noneFoundLabel;
private CustomTreeView selectionTreeView;
@@ -460,7 +460,7 @@ namespace CreamInstaller.Forms
private Label progressLabelDLCs;
private CheckBox sortCheckBox;
private FlowLayoutPanel koaloaderFlowPanel;
- private CheckBox koaloaderAllCheckBox;
+ internal CheckBox koaloaderAllCheckBox;
private Button saveButton;
private Button loadButton;
private Button resetKoaloaderButton;
diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/SelectForm.cs
index 9a656d8..096be6c 100644
--- a/CreamInstaller/Forms/SelectForm.cs
+++ b/CreamInstaller/Forms/SelectForm.cs
@@ -25,21 +25,29 @@ internal sealed partial class SelectForm : CustomForm
{
private const string HelpButtonListPrefix = "\n • ";
+ private static SelectForm current;
+
private readonly ConcurrentDictionary remainingDLCs = new();
private readonly ConcurrentDictionary remainingGames = new();
private List<(Platform platform, string id, string name)> programsToScan;
- internal SelectForm()
+ private SelectForm()
{
InitializeComponent();
Text = Program.ApplicationName;
}
- public override ContextMenuStrip ContextMenuStrip => base.ContextMenuStrip ??= new();
-
- private List TreeNodes => GatherTreeNodes(selectionTreeView.Nodes);
+ internal static SelectForm Current
+ {
+ get
+ {
+ if (current is not null && (current.Disposing || current.IsDisposed))
+ current = null;
+ return current ??= new();
+ }
+ }
private static void UpdateRemaining(Label label, ConcurrentDictionary list, string descriptor)
=> label.Text = list.IsEmpty ? "" : $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list.Values).Replace("&", "&&");
@@ -119,7 +127,6 @@ internal sealed partial class SelectForm : CustomForm
}
if (Program.Canceled)
return;
- List treeNodes = TreeNodes;
remainingGames.Clear(); // for display purposes only, otherwise ignorable
remainingDLCs.Clear(); // for display purposes only, otherwise ignorable
List appTasks = new();
@@ -133,20 +140,8 @@ internal sealed partial class SelectForm : CustomForm
await ParadoxLauncher.InstallPath.GetExecutableDirectories(validFunc: path => !Path.GetFileName(path).Contains("bootstrapper")));
if (uninstallAll)
selection.Enabled = true;
- else
- {
- if (allCheckBox.Checked)
- selection.Enabled = true;
- if (koaloaderAllCheckBox.Checked)
- selection.Koaloader = true;
- TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Paradox && s.Name == selection.Id) ?? new TreeNode();
- programNode.Tag = selection.Platform;
- programNode.Name = selection.Id;
- programNode.Text = selection.Name;
- programNode.Checked = selection.Enabled;
- if (programNode.TreeView is null)
- _ = selectionTreeView.Nodes.Add(programNode);
- }
+ else if (selection.TreeNode.TreeView is null)
+ _ = selectionTreeView.Nodes.Add(selection.TreeNode);
RemoveFromRemainingGames("Paradox Launcher");
}
}
@@ -313,10 +308,6 @@ internal sealed partial class SelectForm : CustomForm
}
Selection selection = Selection.GetOrCreate(Platform.Steam, appId, appData?.Name ?? name, gameDirectory, dllDirectories,
await gameDirectory.GetExecutableDirectories(true));
- selection.Enabled = allCheckBox.Checked || selection.DLC.Any(dlc => dlc.Enabled)
- || selection.ExtraSelections.Any(extraSelection => extraSelection.DLC.Any(dlc => dlc.Enabled));
- if (koaloaderAllCheckBox.Checked)
- selection.Koaloader = true;
selection.Product = "https://store.steampowered.com/app/" + appId;
selection.Icon = IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("icon")}.jpg";
selection.SubIcon = appData?.HeaderImage ?? IconGrabber.SteamAppImagesPath
@@ -329,26 +320,13 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
- TreeNode programNode = treeNodes.Find(s => (Platform)s.Tag == selection.Platform && s.Name == appId) ?? new TreeNode();
- programNode.Tag = selection.Platform;
- programNode.Name = appId;
- programNode.Text = appData?.Name ?? name;
- programNode.Checked = selection.Enabled;
- if (programNode.TreeView is null)
- _ = selectionTreeView.Nodes.Add(programNode);
+ if (selection.TreeNode.TreeView is null)
+ _ = selectionTreeView.Nodes.Add(selection.TreeNode);
foreach ((SelectionDLC dlc, _) in dlc)
{
if (Program.Canceled)
return;
dlc.Selection = selection;
- dlc.Enabled = dlc.Name != "Unknown" && allCheckBox.Checked;
- TreeNode dlcNode = treeNodes.Find(s => (DLCType)s.Tag == dlc.Type && s.Name == dlc.Id) ?? new TreeNode();
- dlcNode.Tag = dlc.Type;
- dlcNode.Name = dlc.Id;
- dlcNode.Text = dlc.Name;
- dlcNode.Checked = dlc.Enabled;
- if (dlcNode.Parent is null)
- _ = programNode.Nodes.Add(dlcNode);
}
});
if (Program.Canceled)
@@ -431,10 +409,6 @@ internal sealed partial class SelectForm : CustomForm
}
Selection selection = Selection.GetOrCreate(Platform.Epic, @namespace, name, directory, dllDirectories,
await directory.GetExecutableDirectories(true));
- selection.Enabled = allCheckBox.Checked || selection.DLC.Any(dlc => dlc.Enabled)
- || selection.ExtraSelections.Any(extraSelection => extraSelection.DLC.Any(dlc => dlc.Enabled));
- if (koaloaderAllCheckBox.Checked)
- selection.Koaloader = true;
foreach ((SelectionDLC dlc, _) in entitlements.Where(dlc => dlc.Key.Name == selection.Name))
{
if (Program.Canceled)
@@ -449,57 +423,22 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
- TreeNode programNode = treeNodes.Find(s => (Platform)s.Tag == selection.Platform && s.Name == @namespace) ?? new TreeNode();
- programNode.Tag = selection.Platform;
- programNode.Name = @namespace;
- programNode.Text = name;
- programNode.Checked = selection.Enabled;
- if (programNode.TreeView is null)
- _ = selectionTreeView.Nodes.Add(programNode);
+ if (selection.TreeNode.TreeView is null)
+ _ = selectionTreeView.Nodes.Add(selection.TreeNode);
if (!catalogItems.IsEmpty)
- /*TreeNode catalogItemsNode = treeNodes.Find(node => (Platform)s.Tag == selection.Platform && node.Name == @namespace + "_catalogItems") ?? new();
- catalogItemsNode.Tag = selection.Platform;
- catalogItemsNode.Name = @namespace + "_catalogItems";
- catalogItemsNode.Text = "Catalog Items";
- catalogItemsNode.Checked = selection.DLC.Any(dlc => dlc.Type is DLCType.EpicCatalogItem && dlc.Enabled);
- if (catalogItemsNode.Parent is null)
- _ = programNode.Nodes.Add(catalogItemsNode);*/
foreach ((SelectionDLC dlc, _) in catalogItems)
{
if (Program.Canceled)
return;
dlc.Selection = selection;
- dlc.Enabled = allCheckBox.Checked;
- TreeNode dlcNode = treeNodes.Find(s => (DLCType)s.Tag == dlc.Type && s.Name == dlc.Id) ?? new TreeNode();
- dlcNode.Tag = dlc.Type;
- dlcNode.Name = dlc.Id;
- dlcNode.Text = dlc.Name;
- dlcNode.Checked = dlc.Enabled;
- if (dlcNode.Parent is null)
- _ = programNode.Nodes.Add(dlcNode); //_ = catalogItemsNode.Nodes.Add(dlcNode);
}
if (entitlements.IsEmpty)
return;
- /*TreeNode entitlementsNode = treeNodes.Find(node => (Platform)s.Tag == selection.Platform && node.Name == @namespace + "_entitlements") ?? new();
- entitlementsNode.Name = selection.Platform;
- entitlementsNode.Name = @namespace + "_entitlements";
- entitlementsNode.Text = "Entitlements";
- entitlementsNode.Checked = selection.DLC.Any(dlc => dlc.Type is DLCType.EpicEntitlement && dlc.Enabled);
- if (entitlementsNode.Parent is null)
- _ = programNode.Nodes.Add(entitlementsNode);*/
foreach ((SelectionDLC dlc, _) in entitlements)
{
if (Program.Canceled)
return;
dlc.Selection = selection;
- dlc.Enabled = allCheckBox.Checked;
- TreeNode dlcNode = treeNodes.Find(s => (DLCType)s.Tag == dlc.Type && s.Name == dlc.Id) ?? new TreeNode();
- dlcNode.Tag = dlc.Type;
- dlcNode.Name = dlc.Id;
- dlcNode.Text = dlc.Name;
- dlcNode.Checked = dlc.Enabled;
- if (dlcNode.Parent is null)
- _ = programNode.Nodes.Add(dlcNode); //_ = entitlementsNode.Nodes.Add(dlcNode);
}
});
if (Program.Canceled)
@@ -541,22 +480,13 @@ internal sealed partial class SelectForm : CustomForm
return;
Selection selection = Selection.GetOrCreate(Platform.Ubisoft, gameId, name, gameDirectory, dllDirectories,
await gameDirectory.GetExecutableDirectories(true));
- selection.Enabled = allCheckBox.Checked || selection.DLC.Any(dlc => dlc.Enabled)
- || selection.ExtraSelections.Any(extraSelection => extraSelection.DLC.Any(dlc => dlc.Enabled));
- if (koaloaderAllCheckBox.Checked)
- selection.Koaloader = true;
selection.Icon = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
selectionTreeView.Invoke(delegate
{
if (Program.Canceled)
return;
- TreeNode programNode = treeNodes.Find(s => (Platform)s.Tag == selection.Platform && s.Name == gameId) ?? new TreeNode();
- programNode.Tag = selection.Platform;
- programNode.Name = gameId;
- programNode.Text = name;
- programNode.Checked = selection.Enabled;
- if (programNode.TreeView is null)
- _ = selectionTreeView.Nodes.Add(programNode);
+ if (selection.TreeNode.TreeView is null)
+ _ = selectionTreeView.Nodes.Add(selection.TreeNode);
});
if (Program.Canceled)
return;
@@ -639,7 +569,8 @@ internal sealed partial class SelectForm : CustomForm
progressBar.Value = p;
};
progressLabel.Text = "Quickly gathering games for uninstallation . . . ";
- TreeNodes.ForEach(node => node.Remove());
+ foreach (Selection selection in Selection.All.Keys)
+ selection.TreeNode.Remove();
await GetApplicablePrograms(iProgress, true);
if (!Program.Canceled)
OnUninstall(null, null);
@@ -691,7 +622,8 @@ internal sealed partial class SelectForm : CustomForm
setup = false;
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
Selection.ValidateAll(programsToScan);
- TreeNodes.ForEach(node => node.Remove());
+ foreach (Selection selection in Selection.All.Keys)
+ selection.TreeNode.Remove();
await GetApplicablePrograms(iProgress);
await SteamCMD.Cleanup();
}
@@ -702,7 +634,7 @@ internal sealed partial class SelectForm : CustomForm
allCheckBox.Enabled = selectionTreeView.Enabled;
koaloaderAllCheckBox.Enabled = selectionTreeView.Enabled;
noneFoundLabel.Visible = !selectionTreeView.Enabled;
- installButton.Enabled = Selection.AllEnabled.Count > 0;
+ installButton.Enabled = Selection.AllEnabled.Any();
uninstallButton.Enabled = installButton.Enabled;
saveButton.Enabled = CanSaveDlc();
loadButton.Enabled = CanLoadDlc();
@@ -723,13 +655,12 @@ internal sealed partial class SelectForm : CustomForm
TreeNode node = e.Node;
if (node is null)
return;
- SyncNode(node);
SyncNodeAncestors(node);
SyncNodeDescendants(node);
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
- allCheckBox.Checked = TreeNodes.TrueForAll(node => node.Text == "Unknown" || node.Checked);
+ allCheckBox.Checked = EnumerateTreeNodes(selectionTreeView.Nodes).All(node => node.Text == "Unknown" || node.Checked);
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
- installButton.Enabled = Selection.AllEnabled.Count > 0;
+ installButton.Enabled = Selection.AllEnabled.Any();
uninstallButton.Enabled = installButton.Enabled;
saveButton.Enabled = CanSaveDlc();
resetButton.Enabled = CanResetDlc();
@@ -737,17 +668,11 @@ internal sealed partial class SelectForm : CustomForm
private static void SyncNodeAncestors(TreeNode node)
{
- while (true)
- {
- TreeNode parentNode = node.Parent;
- if (parentNode is not null)
- {
- parentNode.Checked = parentNode.Nodes.Cast().Any(childNode => childNode.Checked);
- node = parentNode;
- continue;
- }
- break;
- }
+ TreeNode parentNode = node.Parent;
+ if (parentNode is null)
+ return;
+ parentNode.Checked = parentNode.Nodes.Cast().Any(childNode => childNode.Checked);
+ SyncNodeAncestors(parentNode);
}
private static void SyncNodeDescendants(TreeNode node)
@@ -755,38 +680,20 @@ internal sealed partial class SelectForm : CustomForm
foreach (TreeNode childNode in node.Nodes)
{
if (childNode.Text == "Unknown")
- return;
+ continue;
childNode.Checked = node.Checked;
- SyncNode(childNode);
SyncNodeDescendants(childNode);
}
}
- private static void SyncNode(TreeNode node)
+ private static IEnumerable EnumerateTreeNodes(TreeNodeCollection nodeCollection)
{
- string id = node.Name;
- Platform platform = (Platform)node.Tag;
- Selection selection = Selection.FromPlatformId(platform, id);
- if (selection is not null)
- {
- selection.Enabled = node.Checked;
- return;
- }
- DLCType type = (DLCType)node.Tag;
- SelectionDLC dlc = SelectionDLC.FromTypeId(type, id);
- if (dlc is not null)
- dlc.Enabled = node.Checked;
- }
-
- private static List GatherTreeNodes(TreeNodeCollection nodeCollection)
- {
- List treeNodes = new();
foreach (TreeNode rootNode in nodeCollection)
{
- treeNodes.Add(rootNode);
- treeNodes.AddRange(GatherTreeNodes(rootNode.Nodes));
+ yield return rootNode;
+ foreach (TreeNode childNode in EnumerateTreeNodes(rootNode.Nodes))
+ yield return childNode;
}
- return treeNodes;
}
private void ShowProgressBar()
@@ -1027,45 +934,44 @@ internal sealed partial class SelectForm : CustomForm
private void OnAllCheckBoxChanged(object sender, EventArgs e)
{
- bool shouldCheck = TreeNodes.Any(node => node.Parent is null && !node.Checked);
- foreach (TreeNode node in TreeNodes.Where(node => node.Parent is null && node.Checked != shouldCheck))
+ bool shouldEnable = Selection.All.Keys.Any(s => !s.Enabled);
+ foreach (Selection selection in Selection.All.Keys.Where(s => s.Enabled != shouldEnable))
{
- node.Checked = shouldCheck;
- OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
+ selection.Enabled = shouldEnable;
+ OnTreeViewNodeCheckedChanged(null, new(selection.TreeNode, TreeViewAction.ByMouse));
}
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
- allCheckBox.Checked = shouldCheck;
+ allCheckBox.Checked = shouldEnable;
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
}
private void OnKoaloaderAllCheckBoxChanged(object sender, EventArgs e)
{
- bool shouldCheck = Selection.AllSafe.Any(selection => !selection.Koaloader);
- foreach (Selection selection in Selection.AllSafe)
- selection.Koaloader = shouldCheck;
+ bool shouldEnable = Selection.All.Keys.Any(selection => !selection.Koaloader);
+ foreach (Selection selection in Selection.All.Keys)
+ selection.Koaloader = shouldEnable;
selectionTreeView.Invalidate();
koaloaderAllCheckBox.CheckedChanged -= OnKoaloaderAllCheckBoxChanged;
- koaloaderAllCheckBox.Checked = shouldCheck;
+ koaloaderAllCheckBox.Checked = shouldEnable;
koaloaderAllCheckBox.CheckedChanged += OnKoaloaderAllCheckBoxChanged;
+ resetKoaloaderButton.Enabled = CanResetKoaloader();
}
private bool AreSelectionsDefault()
- => TreeNodes.All(node => node.Parent is null || node.Tag is not Platform || (node.Text == "Unknown" ? !node.Checked : node.Checked));
+ => EnumerateTreeNodes(selectionTreeView.Nodes).All(node
+ => node.Parent is null || node.Tag is not Platform and not DLCType || (node.Text == "Unknown" ? !node.Checked : node.Checked));
private bool CanSaveDlc() => installButton.Enabled && (ProgramData.ReadDlcChoices().Any() || !AreSelectionsDefault());
private void OnSaveDlc(object sender, EventArgs e)
{
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices().ToList();
- foreach (TreeNode node in TreeNodes)
- if (node.Parent is { } parent && node.Tag is Platform platform)
- {
- if ((node.Text == "Unknown" ? node.Checked : !node.Checked)
- && !choices.Any(c => c.platform == platform && c.gameId == parent.Name && c.dlcId == node.Name))
- choices.Add((platform, node.Parent.Name, node.Name));
- else
- _ = choices.RemoveAll(n => n.platform == platform && n.gameId == parent.Name && n.dlcId == node.Name);
- }
+ foreach (SelectionDLC dlc in SelectionDLC.All.Keys)
+ if ((dlc.Name == "Unknown" ? dlc.Enabled : !dlc.Enabled)
+ && !choices.Any(c => c.platform == dlc.Selection.Platform && c.gameId == dlc.Selection.Id && c.dlcId == dlc.Id))
+ choices.Add((dlc.Selection.Platform, dlc.Selection.Id, dlc.Id));
+ else
+ _ = choices.RemoveAll(n => n.platform == dlc.Selection.Platform && n.gameId == dlc.Selection.Id && n.dlcId == dlc.Id);
ProgramData.WriteDlcChoices(choices);
loadButton.Enabled = CanLoadDlc();
saveButton.Enabled = CanSaveDlc();
@@ -1076,36 +982,35 @@ internal sealed partial class SelectForm : CustomForm
private void OnLoadDlc(object sender, EventArgs e)
{
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices().ToList();
- foreach (TreeNode node in TreeNodes)
- if (node.Parent is { } parent && node.Tag is Platform platform)
- {
- node.Checked = choices.Any(c => c.platform == platform && c.gameId == parent.Name && c.dlcId == node.Name)
- ? node.Text == "Unknown"
- : node.Text != "Unknown";
- OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
- }
+ foreach (SelectionDLC dlc in SelectionDLC.All.Keys)
+ {
+ dlc.Enabled = choices.Any(c => c.platform == dlc.Selection.Platform && c.gameId == dlc.Selection.Id && c.dlcId == dlc.Id)
+ ? dlc.Name == "Unknown"
+ : dlc.Name != "Unknown";
+ OnTreeViewNodeCheckedChanged(null, new(dlc.TreeNode, TreeViewAction.ByMouse));
+ }
}
private bool CanResetDlc() => !AreSelectionsDefault();
private void OnResetDlc(object sender, EventArgs e)
{
- foreach (TreeNode node in TreeNodes.Where(node => node.Parent is not null && node.Tag is Platform))
+ foreach (SelectionDLC dlc in SelectionDLC.All.Keys)
{
- node.Checked = node.Text != "Unknown";
- OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
+ dlc.Enabled = dlc.Name != "Unknown";
+ OnTreeViewNodeCheckedChanged(null, new(dlc.TreeNode, TreeViewAction.ByMouse));
}
resetButton.Enabled = CanResetDlc();
}
- private static bool AreKoaloaderSelectionsDefault() => Selection.AllSafe.All(selection => selection.Koaloader && selection.KoaloaderProxy is null);
+ private static bool AreKoaloaderSelectionsDefault() => Selection.All.Keys.All(selection => selection.Koaloader && selection.KoaloaderProxy is null);
private static bool CanSaveKoaloader() => ProgramData.ReadKoaloaderChoices().Any() || !AreKoaloaderSelectionsDefault();
private void OnSaveKoaloader(object sender, EventArgs e)
{
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices().ToList();
- foreach (Selection selection in Selection.AllSafe)
+ foreach (Selection selection in Selection.All.Keys)
{
_ = choices.RemoveAll(c => c.platform == selection.Platform && c.id == selection.Id);
if (selection.KoaloaderProxy is not null and not Selection.DefaultKoaloaderProxy || !selection.Koaloader)
@@ -1122,7 +1027,7 @@ internal sealed partial class SelectForm : CustomForm
private void OnLoadKoaloader(object sender, EventArgs e)
{
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices().ToList();
- foreach (Selection selection in Selection.AllSafe)
+ foreach (Selection selection in Selection.All.Keys)
if (choices.Any(c => c.platform == selection.Platform && c.id == selection.Id))
{
(Platform platform, string id, string proxy, bool enabled)
@@ -1155,7 +1060,7 @@ internal sealed partial class SelectForm : CustomForm
private void OnResetKoaloader(object sender, EventArgs e)
{
- foreach (Selection selection in Selection.AllSafe)
+ foreach (Selection selection in Selection.All.Keys)
{
selection.Koaloader = true;
selection.KoaloaderProxy = null;
@@ -1169,7 +1074,7 @@ internal sealed partial class SelectForm : CustomForm
saveKoaloaderButton.Enabled = CanSaveKoaloader();
resetKoaloaderButton.Enabled = CanResetKoaloader();
koaloaderAllCheckBox.CheckedChanged -= OnKoaloaderAllCheckBoxChanged;
- koaloaderAllCheckBox.Checked = Selection.AllSafe.All(selection => selection.Koaloader);
+ koaloaderAllCheckBox.Checked = Selection.All.Keys.All(selection => selection.Koaloader);
koaloaderAllCheckBox.CheckedChanged += OnKoaloaderAllCheckBoxChanged;
}
diff --git a/CreamInstaller/Forms/UpdateForm.cs b/CreamInstaller/Forms/UpdateForm.cs
index 6175fa6..ddccab7 100644
--- a/CreamInstaller/Forms/UpdateForm.cs
+++ b/CreamInstaller/Forms/UpdateForm.cs
@@ -32,7 +32,7 @@ internal sealed partial class UpdateForm : CustomForm
private void StartProgram()
{
- SelectForm form = new();
+ SelectForm form = SelectForm.Current;
form.InheritLocation(this);
form.FormClosing += (_, _) => Close();
form.Show();
diff --git a/CreamInstaller/Platforms/Paradox/ParadoxLauncher.cs b/CreamInstaller/Platforms/Paradox/ParadoxLauncher.cs
index 279b5ee..2b72b63 100644
--- a/CreamInstaller/Platforms/Paradox/ParadoxLauncher.cs
+++ b/CreamInstaller/Platforms/Paradox/ParadoxLauncher.cs
@@ -35,11 +35,11 @@ internal static class ParadoxLauncher
if (paradoxLauncher is null)
return;
paradoxLauncher.ExtraSelections.Clear();
- foreach (Selection selection in Selection.AllEnabled.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
+ foreach (Selection selection in Selection.AllEnabled.Where(s => !s.Equals(paradoxLauncher) && s.Publisher == "Paradox Interactive"))
_ = paradoxLauncher.ExtraSelections.Add(selection);
if (paradoxLauncher.ExtraSelections.Count > 0)
return;
- foreach (Selection selection in Selection.AllSafe.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
+ foreach (Selection selection in Selection.All.Keys.Where(s => !s.Equals(paradoxLauncher) && s.Publisher == "Paradox Interactive"))
_ = paradoxLauncher.ExtraSelections.Add(selection);
}
diff --git a/CreamInstaller/Platforms/Steam/SteamCMD.cs b/CreamInstaller/Platforms/Steam/SteamCMD.cs
index b57fae7..b057c41 100644
--- a/CreamInstaller/Platforms/Steam/SteamCMD.cs
+++ b/CreamInstaller/Platforms/Steam/SteamCMD.cs
@@ -55,64 +55,63 @@ internal static class SteamCMD
{
if (Program.Canceled)
return "";
- if (Interlocked.CompareExchange(ref Locks[i], 1, 0) == 0)
+ if (Interlocked.CompareExchange(ref Locks[i], 1, 0) != 0)
+ continue;
+ if (appId != null)
+ {
+ _ = AttemptCount.TryGetValue(appId, out int count);
+ AttemptCount[appId] = ++count;
+ }
+ if (Program.Canceled)
+ return "";
+ ProcessStartInfo processStartInfo = new()
+ {
+ FileName = FilePath, RedirectStandardOutput = true, RedirectStandardInput = true, RedirectStandardError = true,
+ UseShellExecute = false, Arguments = appId is null ? "+quit" : GetArguments(appId), CreateNoWindow = true,
+ StandardInputEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8
+ };
+ Process process = Process.Start(processStartInfo);
+ StringBuilder output = new();
+ StringBuilder appInfo = new();
+ bool appInfoStarted = false;
+ DateTime lastOutput = DateTime.UtcNow;
+ while (process != null)
{
- if (appId != null)
- {
- _ = AttemptCount.TryGetValue(appId, out int count);
- AttemptCount[appId] = ++count;
- }
if (Program.Canceled)
- return "";
- ProcessStartInfo processStartInfo = new()
{
- FileName = FilePath, RedirectStandardOutput = true, RedirectStandardInput = true, RedirectStandardError = true,
- UseShellExecute = false, Arguments = appId is null ? "+quit" : GetArguments(appId), CreateNoWindow = true,
- StandardInputEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8
- };
- Process process = Process.Start(processStartInfo);
- StringBuilder output = new();
- StringBuilder appInfo = new();
- bool appInfoStarted = false;
- DateTime lastOutput = DateTime.UtcNow;
- while (process != null)
- {
- if (Program.Canceled)
- {
- process.Kill(true);
- process.Close();
- break;
- }
- int c = process.StandardOutput.Read();
- if (c != -1)
- {
- lastOutput = DateTime.UtcNow;
- char ch = (char)c;
- if (ch == '{')
- appInfoStarted = true;
- _ = appInfoStarted ? appInfo.Append(ch) : output.Append(ch);
- }
- DateTime now = DateTime.UtcNow;
- TimeSpan timeDiff = now - lastOutput;
- if (!(timeDiff.TotalSeconds > 0.1))
- continue;
process.Kill(true);
process.Close();
- if (appId != null && output.ToString().Contains($"No app info for AppID {appId} found, requesting..."))
- {
- AttemptCount[appId]++;
- processStartInfo.Arguments = GetArguments(appId);
- process = Process.Start(processStartInfo);
- appInfoStarted = false;
- _ = output.Clear();
- _ = appInfo.Clear();
- }
- else
- break;
+ break;
}
- _ = Interlocked.Decrement(ref Locks[i]);
- return appInfo.ToString();
+ int c = process.StandardOutput.Read();
+ if (c != -1)
+ {
+ lastOutput = DateTime.UtcNow;
+ char ch = (char)c;
+ if (ch == '{')
+ appInfoStarted = true;
+ _ = appInfoStarted ? appInfo.Append(ch) : output.Append(ch);
+ }
+ DateTime now = DateTime.UtcNow;
+ TimeSpan timeDiff = now - lastOutput;
+ if (!(timeDiff.TotalSeconds > 0.1))
+ continue;
+ process.Kill(true);
+ process.Close();
+ if (appId != null && output.ToString().Contains($"No app info for AppID {appId} found, requesting..."))
+ {
+ AttemptCount[appId]++;
+ processStartInfo.Arguments = GetArguments(appId);
+ process = Process.Start(processStartInfo);
+ appInfoStarted = false;
+ _ = output.Clear();
+ _ = appInfo.Clear();
+ }
+ else
+ break;
}
+ _ = Interlocked.Decrement(ref Locks[i]);
+ return appInfo.ToString();
}
Thread.Sleep(200);
goto wait_for_lock;
diff --git a/CreamInstaller/Platforms/Steam/SteamLibrary.cs b/CreamInstaller/Platforms/Steam/SteamLibrary.cs
index 77c7fcc..88b6fec 100644
--- a/CreamInstaller/Platforms/Steam/SteamLibrary.cs
+++ b/CreamInstaller/Platforms/Steam/SteamLibrary.cs
@@ -30,10 +30,10 @@ internal static class SteamLibrary
{
if (Program.Canceled)
return games;
- foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in
- (await GetGamesFromLibraryDirectory(libraryDirectory)).Where(game
- => !games.Any(_game => _game.appId == game.appId && _game.gameDirectory == game.gameDirectory)))
- games.Add(game);
+ foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in await GetGamesFromLibraryDirectory(
+ libraryDirectory))
+ if (!games.Any(_game => _game.appId == game.appId && _game.gameDirectory == game.gameDirectory))
+ games.Add(game);
}
return games;
});
diff --git a/CreamInstaller/Program.cs b/CreamInstaller/Program.cs
index 23fc08d..d98100e 100644
--- a/CreamInstaller/Program.cs
+++ b/CreamInstaller/Program.cs
@@ -38,15 +38,9 @@ internal static class Program
internal static readonly string[] ProtectedGameDirectoryExceptions = Array.Empty();
internal static bool IsGameBlocked(string name, string directory = null)
- {
- if (!BlockProtectedGames)
- return false;
- if (ProtectedGames.Contains(name))
- return true;
- if (directory is null || ProtectedGameDirectoryExceptions.Contains(name))
- return false;
- return ProtectedGameDirectories.Any(path => (directory + path).DirectoryExists());
- }
+ => BlockProtectedGames && (ProtectedGames.Contains(name) || directory is not null && !ProtectedGameDirectoryExceptions.Contains(name)
+ && ProtectedGameDirectories.Any(path
+ => (directory + path).DirectoryExists()));
internal static bool AreDllsLockedDialog(Form form, Selection selection)
{
@@ -57,8 +51,8 @@ internal static class Program
using DialogForm dialogForm = new(form);
if (dialogForm.Show(SystemIcons.Error,
$"ERROR: One or more DLLs crucial to unlocker installation are locked for {selection.Name}!"
- + "\n\nThis is commonly caused by the program/game being active or an anti-virus blocking access."
- + "\n\nPlease close the program/game or resolve your anti-virus to continue . . . ", "Retry", "Cancel") == DialogResult.OK)
+ + "\n\nPlease close the program/game or resolve your anti-virus and press retry to continue . . . ", "Retry", "Cancel")
+ == DialogResult.OK)
continue;
}
else
diff --git a/CreamInstaller/Selection.cs b/CreamInstaller/Selection.cs
index 812c42d..0b8a9aa 100644
--- a/CreamInstaller/Selection.cs
+++ b/CreamInstaller/Selection.cs
@@ -2,6 +2,8 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
+using System.Windows.Forms;
+using CreamInstaller.Forms;
using CreamInstaller.Resources;
using CreamInstaller.Utility;
using static CreamInstaller.Resources.Resources;
@@ -27,8 +29,7 @@ internal sealed class Selection : IEquatable
internal readonly string Name;
internal readonly Platform Platform;
internal readonly string RootDirectory;
-
- internal bool Enabled;
+ internal readonly TreeNode TreeNode;
internal string Icon;
internal bool Koaloader;
internal string KoaloaderProxy;
@@ -47,9 +48,19 @@ internal sealed class Selection : IEquatable
DllDirectories = dllDirectories;
ExecutableDirectories = executableDirectories;
_ = All.TryAdd(this, default);
+ TreeNode = new() { Tag = Platform, Name = Id, Text = Name };
+ SelectForm selectForm = SelectForm.Current;
+ if (selectForm is null)
+ return;
+ Enabled = selectForm.allCheckBox.Checked;
+ Koaloader = selectForm.koaloaderAllCheckBox.Checked;
}
- internal IEnumerable DLC => SelectionDLC.AllSafe.Where(dlc => dlc.Selection.Equals(this));
+ internal static IEnumerable AllEnabled => All.Keys.Where(s => s.Enabled);
+
+ internal bool Enabled { get => TreeNode.Checked; set => TreeNode.Checked = value; }
+
+ internal IEnumerable DLC => SelectionDLC.All.Keys.Where(dlc => dlc.Selection.Equals(this));
internal bool AreDllsLocked
{
@@ -92,10 +103,6 @@ internal sealed class Selection : IEquatable
}
}
- internal static HashSet AllSafe => All.Keys.ToHashSet();
-
- internal static HashSet AllEnabled => All.Keys.Where(s => s.Enabled).ToHashSet();
-
public bool Equals(Selection other)
=> other is not null && (ReferenceEquals(this, other) || Id == other.Id && Platform == other.Platform && RootDirectory == other.RootDirectory);
@@ -106,6 +113,7 @@ internal sealed class Selection : IEquatable
private void Remove()
{
_ = All.TryRemove(this, out _);
+ TreeNode.Remove();
foreach (SelectionDLC dlc in DLC)
dlc.Selection = null;
}
@@ -134,11 +142,11 @@ internal sealed class Selection : IEquatable
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan)
{
- foreach (Selection selection in AllSafe)
+ foreach (Selection selection in All.Keys.ToHashSet())
selection.Validate(programsToScan);
}
- internal static Selection FromPlatformId(Platform platform, string gameId) => AllSafe.FirstOrDefault(s => s.Platform == platform && s.Id == gameId);
+ internal static Selection FromPlatformId(Platform platform, string gameId) => All.Keys.FirstOrDefault(s => s.Platform == platform && s.Id == gameId);
public override bool Equals(object obj) => ReferenceEquals(this, obj) || obj is Selection other && Equals(other);
diff --git a/CreamInstaller/SelectionDLC.cs b/CreamInstaller/SelectionDLC.cs
index b83cad8..a718229 100644
--- a/CreamInstaller/SelectionDLC.cs
+++ b/CreamInstaller/SelectionDLC.cs
@@ -1,25 +1,24 @@
using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.Linq;
+using System.Windows.Forms;
namespace CreamInstaller;
public enum DLCType
{
- None = 0, Steam, SteamHidden, EpicCatalogItem,
- EpicEntitlement
+ None = 0, Steam, SteamHidden,
+ EpicCatalogItem, EpicEntitlement
}
internal sealed class SelectionDLC : IEquatable
{
- private static readonly ConcurrentDictionary All = new();
+ internal static readonly ConcurrentDictionary All = new();
internal readonly string Id;
internal readonly string Name;
+ internal readonly TreeNode TreeNode;
internal readonly DLCType Type;
-
- internal bool Enabled;
internal string Icon;
internal string Product;
internal string Publisher;
@@ -30,25 +29,38 @@ internal sealed class SelectionDLC : IEquatable
Type = type;
Id = id;
Name = name;
+ TreeNode = new() { Tag = Type, Name = Id, Text = Name };
}
+ internal bool Enabled { get => TreeNode.Checked; set => TreeNode.Checked = value; }
+
internal Selection Selection
{
get => selection;
set
{
+ if (ReferenceEquals(selection, value))
+ return;
selection = value;
- _ = value is null ? All.TryRemove(this, out _) : All.TryAdd(this, default);
+ if (value is null)
+ {
+ _ = All.TryRemove(this, out _);
+ TreeNode.Remove();
+ }
+ else
+ {
+ _ = All.TryAdd(this, default);
+ _ = value.TreeNode.Nodes.Add(TreeNode);
+ Enabled = Name != "Unknown" && value.Enabled;
+ }
}
}
- internal static HashSet AllSafe => All.Keys.ToHashSet();
-
public bool Equals(SelectionDLC other) => other is not null && (ReferenceEquals(this, other) || Id == other.Id && Type == other.Type);
internal static SelectionDLC GetOrCreate(DLCType type, string id, string name) => FromTypeId(type, id) ?? new SelectionDLC(type, id, name);
- internal static SelectionDLC FromTypeId(DLCType Type, string dlcId) => AllSafe.FirstOrDefault(dlc => dlc.Type == Type && dlc.Id == dlcId);
+ internal static SelectionDLC FromTypeId(DLCType Type, string dlcId) => All.Keys.FirstOrDefault(dlc => dlc.Type == Type && dlc.Id == dlcId);
public override bool Equals(object obj) => ReferenceEquals(this, obj) || obj is SelectionDLC other && Equals(other);