diff --git a/CreamInstaller/Components/CustomTreeView.cs b/CreamInstaller/Components/CustomTreeView.cs
index 1fcf0e3..3da0876 100644
--- a/CreamInstaller/Components/CustomTreeView.cs
+++ b/CreamInstaller/Components/CustomTreeView.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Drawing;
using System.Windows.Forms;
@@ -14,10 +15,16 @@ internal class CustomTreeView : TreeView
base.WndProc(ref m);
}
+ private class TreeNodeSorter : IComparer
+ {
+ public int Compare(object a, object b) => AppIdComparer.Comparer.Compare((a as TreeNode).Name, (b as TreeNode).Name);
+ }
+
internal CustomTreeView() : base()
{
DrawMode = TreeViewDrawMode.OwnerDrawAll;
DrawNode += new DrawTreeNodeEventHandler(DrawTreeNode);
+ TreeViewNodeSorter = new TreeNodeSorter();
}
private void DrawTreeNode(object sender, DrawTreeNodeEventArgs e)
@@ -35,7 +42,7 @@ internal class CustomTreeView : TreeView
string subText = node.Name;
if (string.IsNullOrWhiteSpace(subText) || subText == "ParadoxLauncher"
- || ProgramSelection.FromId(subText) is null && ProgramSelection.GetDlcFromId(subText) is null)
+ || node.Tag is null && ProgramSelection.FromId(subText) is null && ProgramSelection.GetDlcFromId(subText) is null)
return;
Size subSize = TextRenderer.MeasureText(graphics, subText, subFont);
@@ -46,4 +53,4 @@ internal class CustomTreeView : TreeView
Point subLocation = new(location.X - 1, location.Y + 1);
TextRenderer.DrawText(graphics, subText, subFont, subLocation, Color.Gray);
}
-}
+}
\ No newline at end of file
diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj
index 3a2bf21..81b5ae9 100644
--- a/CreamInstaller/CreamInstaller.csproj
+++ b/CreamInstaller/CreamInstaller.csproj
@@ -5,7 +5,7 @@
True
Resources\ini.ico
true
- 3.2.3.1
+ 3.3.0.0
Resources\ini.ico
LICENSE
2021, pointfeev (https://github.com/pointfeev)
@@ -42,6 +42,9 @@
+
+ Form
+
@@ -51,6 +54,9 @@
+
+ Designer
+
ResXFileCodeGenerator
Resources.Designer.cs
diff --git a/CreamInstaller/Epic/EpicLibrary.cs b/CreamInstaller/Epic/EpicLibrary.cs
index 675cfea..9db641c 100644
--- a/CreamInstaller/Epic/EpicLibrary.cs
+++ b/CreamInstaller/Epic/EpicLibrary.cs
@@ -2,6 +2,7 @@
using System.IO;
using System.Linq;
using System.Text.Json;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
@@ -31,6 +32,7 @@ internal static class EpicLibrary
foreach (string file in files)
{
if (Program.Canceled) return games;
+ Thread.Sleep(0);
string json = File.ReadAllText(file);
try
{
@@ -58,6 +60,7 @@ internal static class EpicLibrary
foreach (string _directory in directories)
{
if (Program.Canceled) return null;
+ Thread.Sleep(0);
try
{
List moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
diff --git a/CreamInstaller/Forms/DialogForm.cs b/CreamInstaller/Forms/DialogForm.cs
index ef294e8..4ce0447 100644
--- a/CreamInstaller/Forms/DialogForm.cs
+++ b/CreamInstaller/Forms/DialogForm.cs
@@ -30,7 +30,7 @@ internal partial class DialogForm : CustomForm
return ShowDialog();
}
- internal void OnResize(object s, EventArgs e) =>
+ private void OnResize(object s, EventArgs e) =>
Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
? Program.ApplicationNameShort
: Program.ApplicationName;
diff --git a/CreamInstaller/Forms/SelectDialogForm.Designer.cs b/CreamInstaller/Forms/SelectDialogForm.Designer.cs
new file mode 100644
index 0000000..fb5a51a
--- /dev/null
+++ b/CreamInstaller/Forms/SelectDialogForm.Designer.cs
@@ -0,0 +1,159 @@
+
+namespace CreamInstaller
+{
+ partial class SelectDialogForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.acceptButton = new System.Windows.Forms.Button();
+ this.groupBox = new System.Windows.Forms.GroupBox();
+ this.selectionTreeView = new Components.CustomTreeView();
+ this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
+ this.allCheckBox = new System.Windows.Forms.CheckBox();
+ this.cancelButton = new System.Windows.Forms.Button();
+ this.groupBox.SuspendLayout();
+ this.flowLayoutPanel2.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // acceptButton
+ //
+ this.acceptButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.acceptButton.AutoSize = true;
+ this.acceptButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.acceptButton.DialogResult = System.Windows.Forms.DialogResult.OK;
+ this.acceptButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
+ this.acceptButton.Location = new System.Drawing.Point(360, 243);
+ this.acceptButton.Name = "acceptButton";
+ this.acceptButton.Padding = new System.Windows.Forms.Padding(12, 0, 12, 0);
+ this.acceptButton.Size = new System.Drawing.Size(61, 24);
+ this.acceptButton.TabIndex = 0;
+ this.acceptButton.Text = "OK";
+ this.acceptButton.UseVisualStyleBackColor = true;
+ //
+ // groupBox
+ //
+ this.groupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.groupBox.Controls.Add(this.selectionTreeView);
+ this.groupBox.Controls.Add(this.flowLayoutPanel2);
+ this.groupBox.Location = new System.Drawing.Point(12, 12);
+ this.groupBox.MinimumSize = new System.Drawing.Size(240, 40);
+ this.groupBox.Name = "groupBox";
+ this.groupBox.Size = new System.Drawing.Size(409, 225);
+ this.groupBox.TabIndex = 3;
+ this.groupBox.TabStop = false;
+ this.groupBox.Text = "Choices";
+ //
+ // selectionTreeView
+ //
+ this.selectionTreeView.BackColor = System.Drawing.SystemColors.Control;
+ this.selectionTreeView.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.selectionTreeView.CheckBoxes = true;
+ this.selectionTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.selectionTreeView.DrawMode = System.Windows.Forms.TreeViewDrawMode.OwnerDrawAll;
+ this.selectionTreeView.Location = new System.Drawing.Point(3, 19);
+ this.selectionTreeView.Name = "selectionTreeView";
+ this.selectionTreeView.ShowLines = false;
+ this.selectionTreeView.ShowPlusMinus = false;
+ this.selectionTreeView.ShowRootLines = false;
+ this.selectionTreeView.Size = new System.Drawing.Size(403, 203);
+ this.selectionTreeView.Sorted = true;
+ this.selectionTreeView.TabIndex = 0;
+ //
+ // flowLayoutPanel2
+ //
+ this.flowLayoutPanel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.flowLayoutPanel2.AutoSize = true;
+ this.flowLayoutPanel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.flowLayoutPanel2.Controls.Add(this.allCheckBox);
+ this.flowLayoutPanel2.Location = new System.Drawing.Point(366, -1);
+ this.flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
+ this.flowLayoutPanel2.Name = "flowLayoutPanel2";
+ this.flowLayoutPanel2.Size = new System.Drawing.Size(37, 19);
+ this.flowLayoutPanel2.TabIndex = 1007;
+ //
+ // allCheckBox
+ //
+ this.allCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.allCheckBox.FlatStyle = System.Windows.Forms.FlatStyle.System;
+ this.allCheckBox.Location = new System.Drawing.Point(3, 0);
+ this.allCheckBox.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0);
+ this.allCheckBox.Name = "allCheckBox";
+ this.allCheckBox.Size = new System.Drawing.Size(34, 19);
+ this.allCheckBox.TabIndex = 1;
+ this.allCheckBox.Text = "All";
+ this.allCheckBox.CheckedChanged += new System.EventHandler(this.OnAllCheckBoxChanged);
+ //
+ // cancelButton
+ //
+ this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.cancelButton.AutoSize = true;
+ this.cancelButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.cancelButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
+ this.cancelButton.Location = new System.Drawing.Point(12, 243);
+ this.cancelButton.Name = "cancelButton";
+ this.cancelButton.Padding = new System.Windows.Forms.Padding(12, 0, 12, 0);
+ this.cancelButton.Size = new System.Drawing.Size(81, 24);
+ this.cancelButton.TabIndex = 4;
+ this.cancelButton.Text = "Cancel";
+ this.cancelButton.UseVisualStyleBackColor = true;
+ //
+ // SelectDialogForm
+ //
+ this.AcceptButton = this.acceptButton;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(433, 279);
+ this.Controls.Add(this.cancelButton);
+ this.Controls.Add(this.acceptButton);
+ this.Controls.Add(this.groupBox);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "SelectDialogForm";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "SelectDialogForm";
+ this.TopMost = true;
+ this.groupBox.ResumeLayout(false);
+ this.groupBox.PerformLayout();
+ this.flowLayoutPanel2.ResumeLayout(false);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+ private System.Windows.Forms.Button acceptButton;
+ private System.Windows.Forms.GroupBox groupBox;
+ private Components.CustomTreeView selectionTreeView;
+ private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
+ private System.Windows.Forms.CheckBox allCheckBox;
+ private System.Windows.Forms.Button cancelButton;
+ }
+}
\ No newline at end of file
diff --git a/CreamInstaller/Forms/SelectDialogForm.cs b/CreamInstaller/Forms/SelectDialogForm.cs
new file mode 100644
index 0000000..4728444
--- /dev/null
+++ b/CreamInstaller/Forms/SelectDialogForm.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+
+using CreamInstaller.Components;
+
+namespace CreamInstaller;
+
+internal partial class SelectDialogForm : CustomForm
+{
+ internal SelectDialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
+
+ private readonly List<(string platform, string id, string name)> selected = new();
+ internal List<(string platform, string id, string name)> QueryUser(string groupBoxText, List<(string platform, string id, string name, bool alreadySelected)> choices)
+ {
+ groupBox.Text = groupBoxText;
+ allCheckBox.Enabled = false;
+ acceptButton.Enabled = false;
+ selectionTreeView.AfterCheck += OnTreeNodeChecked;
+ foreach ((string platform, string id, string name, bool alreadySelected) in choices)
+ {
+ TreeNode node = new();
+ node.Tag = platform;
+ node.Name = id;
+ node.Text = name;
+ node.Checked = alreadySelected;
+ OnTreeNodeChecked(node);
+ selectionTreeView.Nodes.Add(node);
+ }
+ allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
+ allCheckBox.Checked = selectionTreeView.Nodes.Cast().All(n => n.Checked);
+ allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
+ allCheckBox.Enabled = true;
+ acceptButton.Enabled = selected.Any();
+ OnResize(null, null);
+ Resize += OnResize;
+ return ShowDialog() == DialogResult.OK ? selected : null;
+ }
+
+ private void OnTreeNodeChecked(object sender, TreeViewEventArgs e)
+ {
+ OnTreeNodeChecked(e.Node);
+ acceptButton.Enabled = selected.Any();
+ }
+
+ private void OnTreeNodeChecked(TreeNode node)
+ {
+ string id = node.Name;
+ if (node.Checked)
+ selected.Add((node.Tag as string, id, node.Text));
+ else
+ selected.RemoveAll(s => s.id == id);
+ allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
+ allCheckBox.Checked = selectionTreeView.Nodes.Cast().All(n => n.Checked);
+ allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
+ }
+
+ private void OnResize(object s, EventArgs e) =>
+ Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
+ ? Program.ApplicationNameShort
+ : Program.ApplicationName;
+
+ private void OnAllCheckBoxChanged(object sender, EventArgs e)
+ {
+ bool shouldCheck = false;
+ foreach (TreeNode node in selectionTreeView.Nodes)
+ if (!node.Checked)
+ shouldCheck = true;
+ foreach (TreeNode node in selectionTreeView.Nodes)
+ {
+ node.Checked = shouldCheck;
+ OnTreeNodeChecked(node);
+ }
+ allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
+ allCheckBox.Checked = shouldCheck;
+ allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
+ }
+}
diff --git a/CreamInstaller/Forms/SelectDialogForm.resx b/CreamInstaller/Forms/SelectDialogForm.resx
new file mode 100644
index 0000000..f298a7b
--- /dev/null
+++ b/CreamInstaller/Forms/SelectDialogForm.resx
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/SelectForm.cs
index 9c2364f..2a96787 100644
--- a/CreamInstaller/Forms/SelectForm.cs
+++ b/CreamInstaller/Forms/SelectForm.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
@@ -82,6 +81,7 @@ internal partial class SelectForm : CustomForm
private async Task GetApplicablePrograms(IProgress progress)
{
+ if (ProgramsToScan is null || !ProgramsToScan.Any()) return;
int TotalGameCount = 0;
int CompleteGameCount = 0;
void AddToRemainingGames(string gameName)
@@ -99,7 +99,7 @@ internal partial class SelectForm : CustomForm
RemainingGames.Clear(); // for display purposes only, otherwise ignorable
RemainingDLCs.Clear(); // for display purposes only, otherwise ignorable
List appTasks = new();
- if (Directory.Exists(ParadoxLauncher.InstallPath))
+ if (Directory.Exists(ParadoxLauncher.InstallPath) && ProgramsToScan.Any(c => c.platform == "Paradox" && c.id == "ParadoxLauncher"))
{
ProgramSelection selection = ProgramSelection.FromId("ParadoxLauncher");
selection ??= new();
@@ -119,7 +119,7 @@ internal partial class SelectForm : CustomForm
programNode.Remove();
selectionTreeView.Nodes.Add(programNode);
}
- if (Directory.Exists(SteamLibrary.InstallPath))
+ if (Directory.Exists(SteamLibrary.InstallPath) && ProgramsToScan.Any(c => c.platform == "Steam"))
{
List> steamGames = await SteamLibrary.GetGames();
foreach (Tuple program in steamGames)
@@ -129,10 +129,9 @@ internal partial class SelectForm : CustomForm
string branch = program.Item3;
int buildId = program.Item4;
string directory = program.Item5;
- Thread.Sleep(0);
- ProgramSelection selection = ProgramSelection.FromId(appId);
if (Program.Canceled) return;
- if (Program.IsGameBlocked(name, directory)) continue;
+ Thread.Sleep(0);
+ if (Program.IsGameBlocked(name, directory) || !ProgramsToScan.Any(c => c.id == appId)) continue;
AddToRemainingGames(name);
Task task = Task.Run(async () =>
{
@@ -162,6 +161,7 @@ internal partial class SelectForm : CustomForm
foreach (string dlcAppId in dlcIds)
{
if (Program.Canceled) return;
+ Thread.Sleep(0);
AddToRemainingDLCs(dlcAppId);
Task task = Task.Run(async () =>
{
@@ -209,7 +209,7 @@ internal partial class SelectForm : CustomForm
await task;
}
- selection ??= new();
+ ProgramSelection selection = ProgramSelection.FromId(appId) ?? new();
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraDlc.Any();
selection.Usable = true;
selection.Id = appId;
@@ -255,7 +255,7 @@ internal partial class SelectForm : CustomForm
appTasks.Add(task);
}
}
- if (Directory.Exists(EpicLibrary.EpicAppDataPath))
+ if (Directory.Exists(EpicLibrary.EpicAppDataPath) && ProgramsToScan.Any(c => c.platform == "Epic"))
{
List epicGames = await EpicLibrary.GetGames();
foreach (Manifest manifest in epicGames)
@@ -263,10 +263,9 @@ internal partial class SelectForm : CustomForm
string @namespace = manifest.CatalogNamespace;
string name = manifest.DisplayName;
string directory = manifest.InstallLocation;
- Thread.Sleep(0);
- ProgramSelection selection = ProgramSelection.FromId(@namespace);
if (Program.Canceled) return;
- if (Program.IsGameBlocked(name, directory)) continue;
+ Thread.Sleep(0);
+ if (Program.IsGameBlocked(name, directory) || !ProgramsToScan.Any(c => c.id == @namespace)) continue;
AddToRemainingGames(name);
Task task = Task.Run(async () =>
{
@@ -292,6 +291,7 @@ internal partial class SelectForm : CustomForm
Task task = Task.Run(() =>
{
if (Program.Canceled) return;
+ Thread.Sleep(0);
entitlements[id] = (name, product, icon, developer);
RemoveFromRemainingDLCs(id);
});
@@ -311,7 +311,7 @@ internal partial class SelectForm : CustomForm
await task;
}
- selection ??= new();
+ ProgramSelection selection = ProgramSelection.FromId(@namespace) ?? new();
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraDlc.Any();
selection.Usable = true;
selection.Id = @namespace;
@@ -356,7 +356,7 @@ internal partial class SelectForm : CustomForm
programNode.Nodes.Add(entitlementsNode);*/
foreach (KeyValuePair pair in entitlements)
{
- if (Program.Canceled || programNode is null/* || entitlementsNode is null*/) return;
+ if (programNode is null/* || entitlementsNode is null*/) return;
Thread.Sleep(0);
string dlcId = pair.Key;
(DlcType type, string name, string icon) dlcApp = (DlcType.Entitlement, pair.Value.name, pair.Value.icon);
@@ -384,7 +384,8 @@ internal partial class SelectForm : CustomForm
}
}
- private async void OnLoad()
+ private List<(string platform, string id, string name)> ProgramsToScan;
+ private async void OnLoad(bool selectGamesToScan = false)
{
Program.Canceled = false;
blockedGamesCheckBox.Enabled = false;
@@ -396,8 +397,33 @@ internal partial class SelectForm : CustomForm
installButton.Enabled = false;
uninstallButton.Enabled = installButton.Enabled;
selectionTreeView.Enabled = false;
+ progressLabel.Text = "Waiting for user to select which programs/games to scan . . .";
ShowProgressBar();
+ if (ProgramsToScan is null || !ProgramsToScan.Any() || selectGamesToScan)
+ {
+ List<(string platform, string id, string name, bool alreadySelected)> gameChoices = new();
+ if (Directory.Exists(ParadoxLauncher.InstallPath))
+ gameChoices.Add(("Paradox", "ParadoxLauncher", "Paradox Launcher", ProgramsToScan is not null && ProgramsToScan.Any(p => p.id == "ParadoxLauncher")));
+ if (Directory.Exists(SteamLibrary.InstallPath))
+ foreach (Tuple program in await SteamLibrary.GetGames())
+ if (!Program.IsGameBlocked(program.Item1, program.Item5))
+ gameChoices.Add(("Steam", program.Item1, program.Item2, ProgramsToScan is not null && ProgramsToScan.Any(p => p.id == program.Item1)));
+ if (Directory.Exists(EpicLibrary.EpicAppDataPath))
+ foreach (Manifest manifest in await EpicLibrary.GetGames())
+ if (!Program.IsGameBlocked(manifest.DisplayName, manifest.InstallLocation))
+ gameChoices.Add(("Epic", manifest.CatalogNamespace, manifest.DisplayName, ProgramsToScan is not null && ProgramsToScan.Any(p => p.id == manifest.CatalogNamespace)));
+ if (gameChoices.Any())
+ {
+ using SelectDialogForm form = new(this);
+ List<(string platform, string id, string name)> choices = form.QueryUser("Choose which programs/games to scan:", gameChoices);
+ if (choices is not null) ProgramsToScan = choices;
+ noneFoundLabel.Text = "None of the chosen programs/games were CreamAPI-applicable or ScreamAPI-applicable!\n\nPress the \"Rescan Programs / Games\" button to re-choose.";
+ }
+ else
+ noneFoundLabel.Text = "No CreamAPI-applicable or ScreamAPI-applicable programs/games were found on your computer!";
+ }
+
bool setup = true;
int maxProgress = 0;
int curProgress = 0;
@@ -406,6 +432,7 @@ internal partial class SelectForm : CustomForm
progress.ProgressChanged += (sender, _progress) =>
{
if (Program.Canceled) return;
+ Thread.Sleep(0);
if (_progress < 0 || _progress > maxProgress) maxProgress = -_progress;
else curProgress = _progress;
int p = Math.Max(Math.Min((int)((float)(curProgress / (float)maxProgress) * 100), 100), 0);
@@ -415,14 +442,14 @@ internal partial class SelectForm : CustomForm
};
await ProgramData.Setup();
- if (Directory.Exists(SteamLibrary.InstallPath))
+ if (Directory.Exists(SteamLibrary.InstallPath) && ProgramsToScan is not null && ProgramsToScan.Any(c => c.platform == "Steam"))
{
progressLabel.Text = $"Setting up SteamCMD . . . ";
await SteamCMD.Setup(iProgress);
}
setup = false;
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
- ProgramSelection.ValidateAll();
+ ProgramSelection.ValidateAll(ProgramsToScan);
TreeNodes.ForEach(node => node.Remove());
await GetApplicablePrograms(iProgress);
await SteamCMD.Cleanup();
@@ -502,11 +529,6 @@ internal partial class SelectForm : CustomForm
return treeNodes;
}
- private class TreeNodeSorter : IComparer
- {
- public int Compare(object a, object b) => AppIdComparer.Comparer.Compare((a as TreeNode).Name, (b as TreeNode).Name);
- }
-
private void ShowProgressBar()
{
progressBar.Value = 0;
@@ -543,7 +565,6 @@ internal partial class SelectForm : CustomForm
try
{
HideProgressBar();
- selectionTreeView.TreeViewNodeSorter = new TreeNodeSorter();
selectionTreeView.AfterCheck += OnTreeViewNodeCheckedChanged;
selectionTreeView.NodeMouseClick += (sender, e) =>
{
@@ -649,7 +670,7 @@ internal partial class SelectForm : CustomForm
}
contextMenuStrip.Show(selectionTreeView, e.Location);
};
- OnLoad();
+ OnLoad(true);
}
catch (Exception e)
{
@@ -682,7 +703,7 @@ internal partial class SelectForm : CustomForm
private void OnUninstall(object sender, EventArgs e) => OnAccept(true);
- private void OnScan(object sender, EventArgs e) => OnLoad();
+ private void OnScan(object sender, EventArgs e) => OnLoad(true);
private void OnCancel(object sender, EventArgs e)
{
@@ -711,7 +732,7 @@ internal partial class SelectForm : CustomForm
private void OnBlockProtectedGamesCheckBoxChanged(object sender, EventArgs e)
{
Program.BlockProtectedGames = blockedGamesCheckBox.Checked;
- OnLoad();
+ OnLoad(true);
}
private readonly string helpButtonListPrefix = "\n • ";
diff --git a/CreamInstaller/Forms/SelectForm.resx b/CreamInstaller/Forms/SelectForm.resx
index 97370c1..f298a7b 100644
--- a/CreamInstaller/Forms/SelectForm.resx
+++ b/CreamInstaller/Forms/SelectForm.resx
@@ -57,7 +57,4 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- 17, 17
-
\ No newline at end of file
diff --git a/CreamInstaller/Program.cs b/CreamInstaller/Program.cs
index d3d9d52..95150f6 100644
--- a/CreamInstaller/Program.cs
+++ b/CreamInstaller/Program.cs
@@ -26,11 +26,11 @@ internal static class Program
internal static readonly string[] ProtectedGameDirectories = { @"\EasyAntiCheat", @"\BattlEye" }; // DLL detections
internal static readonly string[] ProtectedGameDirectoryExceptions = { "Arma 3" }; // Arma 3's BattlEye doesn't detect DLL changes?
- internal static bool IsGameBlocked(string name, string directory)
+ internal static bool IsGameBlocked(string name, string directory = null)
{
if (!BlockProtectedGames) return false;
if (ProtectedGameNames.Contains(name)) return true;
- if (!ProtectedGameDirectoryExceptions.Contains(name))
+ if (directory is not null && !ProtectedGameDirectoryExceptions.Contains(name))
foreach (string path in ProtectedGameDirectories)
if (Directory.Exists(directory + path)) return true;
return false;
diff --git a/CreamInstaller/ProgramSelection.cs b/CreamInstaller/ProgramSelection.cs
index e81263e..57f1b69 100644
--- a/CreamInstaller/ProgramSelection.cs
+++ b/CreamInstaller/ProgramSelection.cs
@@ -101,8 +101,20 @@ internal class ProgramSelection
if (!DllDirectories.Any()) All.Remove(this);
}
+ internal void Validate(List<(string platform, string id, string name)> programsToScan)
+ {
+ if (programsToScan is null || !programsToScan.Any(p => p.id == Id))
+ {
+ All.Remove(this);
+ return;
+ }
+ Validate();
+ }
+
internal static void ValidateAll() => AllSafe.ForEach(selection => selection.Validate());
+ internal static void ValidateAll(List<(string platform, string id, string name)> programsToScan) => AllSafe.ForEach(selection => selection.Validate(programsToScan));
+
internal static List All = new();
internal static List AllSafe => All.ToList();
diff --git a/CreamInstaller/Steam/SteamCMD.cs b/CreamInstaller/Steam/SteamCMD.cs
index e3f4ece..4ea4e4e 100644
--- a/CreamInstaller/Steam/SteamCMD.cs
+++ b/CreamInstaller/Steam/SteamCMD.cs
@@ -36,9 +36,11 @@ internal static class SteamCMD
{
wait_for_lock:
if (Program.Canceled) return "";
+ Thread.Sleep(0);
for (int i = 0; i < locks.Length; i++)
{
if (Program.Canceled) return "";
+ Thread.Sleep(0);
if (Interlocked.CompareExchange(ref locks[i], 1, 0) == 0)
{
if (appId is not null)
@@ -107,7 +109,7 @@ internal static class SteamCMD
Interlocked.Decrement(ref locks[i]);
return appInfo;
}
- Thread.Sleep(0);
+ Thread.Sleep(200);
}
Thread.Sleep(200);
goto wait_for_lock;
@@ -121,11 +123,10 @@ internal static class SteamCMD
await Cleanup();
if (!File.Exists(FilePath))
{
- using (HttpClient httpClient = new())
- {
- byte[] file = await httpClient.GetByteArrayAsync(new Uri("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"));
- file.Write(ArchivePath);
- }
+ HttpClient httpClient = HttpClientManager.HttpClient;
+ if (httpClient is null) return;
+ byte[] file = await httpClient.GetByteArrayAsync(new Uri("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"));
+ file.Write(ArchivePath);
ZipFile.ExtractToDirectory(ArchivePath, DirectoryPath);
File.Delete(ArchivePath);
}
diff --git a/CreamInstaller/Steam/SteamLibrary.cs b/CreamInstaller/Steam/SteamLibrary.cs
index 3bcb8ec..bdb6c53 100644
--- a/CreamInstaller/Steam/SteamLibrary.cs
+++ b/CreamInstaller/Steam/SteamLibrary.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using Gameloop.Vdf.Linq;
@@ -30,6 +31,8 @@ internal static class SteamLibrary
List gameLibraryDirectories = await GetLibraryDirectories();
foreach (string libraryDirectory in gameLibraryDirectories)
{
+ if (Program.Canceled) return games;
+ Thread.Sleep(0);
List> directoryGames = await GetGamesFromLibraryDirectory(libraryDirectory);
if (directoryGames is not null)
foreach (Tuple game in directoryGames)
@@ -54,6 +57,7 @@ internal static class SteamLibrary
foreach (string _directory in directories)
{
if (Program.Canceled) return null;
+ Thread.Sleep(0);
try
{
List moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
@@ -72,6 +76,7 @@ internal static class SteamLibrary
foreach (string file in files)
{
if (Program.Canceled) return null;
+ Thread.Sleep(0);
if (ValveDataFile.TryDeserialize(File.ReadAllText(file, Encoding.UTF8), out VProperty result))
{
string appId = result.Value.GetChild("appid")?.ToString();
diff --git a/CreamInstaller/Utility/HttpClientManager.cs b/CreamInstaller/Utility/HttpClientManager.cs
index 7dc9961..0a9e6c8 100644
--- a/CreamInstaller/Utility/HttpClientManager.cs
+++ b/CreamInstaller/Utility/HttpClientManager.cs
@@ -14,7 +14,7 @@ internal static class HttpClientManager
internal static void Setup()
{
HttpClient = new();
- HttpClient.DefaultRequestHeaders.Add("User-Agent", $"{Environment.MachineName}CI{Application.ProductVersion.Replace(".", "")}{Environment.UserName}");
+ HttpClient.DefaultRequestHeaders.Add("User-Agent", $"CI{Application.ProductVersion.Replace(".", "")}");
}
internal static async Task EnsureGet(string url)