- Added extra labels to the selection form progress section that display remaining games and DLCs, replacing the "(#/#)" text
- Fixed a harmless control invoke exception that happens when the program is closed
- Fixed a harmless bug with duplicates being included in the games to be gathered
This commit is contained in:
pointfeev 2022-02-05 02:04:22 -05:00
parent bb8f197260
commit 0d4c1630d6
7 changed files with 207 additions and 42 deletions

View file

@ -100,7 +100,7 @@ internal class ProgramSelection
internal void Validate()
{
if (Program.BlockProtectedGames && Program.IsGameBlocked(Name, RootDirectory))
if (Program.IsGameBlocked(Name, RootDirectory))
{
All.Remove(this);
return;

View file

@ -131,12 +131,12 @@ internal static class SteamCMD
VToken extended = appInfo.Value.GetChild("extended");
if (extended is not null)
foreach (VProperty property in extended)
if (property.Key.ToString() == "listofdlc")
if (property.Key == "listofdlc")
foreach (string id in property.Value.ToString().Split(","))
if (int.TryParse(id, out int appId) && !dlcIds.Contains(appId)) dlcIds.Add(appId);
VToken depots = appInfo.Value.GetChild("depots");
if (depots is not null) foreach (VProperty property in depots)
if (int.TryParse(property.Key.ToString(), out int _)
if (int.TryParse(property.Key, out int _)
&& int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appid)
&& !dlcIds.Contains(appid))
dlcIds.Add(appid);

View file

@ -5,7 +5,7 @@
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<Version>2.2.4.4</Version>
<Version>2.3.0.0</Version>
<PackageIcon>Resources\ini.ico</PackageIcon>
<PackageIconUrl />
<Description>Automatically generates and installs CreamAPI files for Steam games on the user's computer. It can also generate and install CreamAPI for the Paradox Launcher should the user select a Paradox Interactive game.</Description>

View file

@ -113,7 +113,7 @@ internal partial class MainForm : CustomForm
document.LoadHtml(reader.ReadToEnd());
foreach (HtmlNode node in document.DocumentNode.SelectNodes("//div[@data-test-selector='body-content']/ul/li"))
{
changelogTreeView.Invoke((MethodInvoker)delegate
changelogTreeView.TryMethodInvoke(delegate
{
TreeNode change = new();
change.Text = $"{HttpUtility.HtmlDecode(node.InnerText)}";

View file

@ -43,11 +43,13 @@ namespace CreamInstaller
this.selectionTreeView = new CreamInstaller.CustomTreeView();
this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
this.allCheckBox = new System.Windows.Forms.CheckBox();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.progressBar = new System.Windows.Forms.ProgressBar();
this.progressLabel = new System.Windows.Forms.Label();
this.scanButton = new System.Windows.Forms.Button();
this.uninstallButton = new System.Windows.Forms.Button();
this.nodeContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
this.progressLabelGames = new System.Windows.Forms.Label();
this.progressLabelDLCs = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.flowLayoutPanel1.SuspendLayout();
this.flowLayoutPanel2.SuspendLayout();
@ -97,19 +99,17 @@ namespace CreamInstaller
this.groupBox1.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(560, 308);
this.groupBox1.Size = new System.Drawing.Size(560, 240);
this.groupBox1.TabIndex = 8;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Programs / Games";
//
// noneFoundLabel
//
this.noneFoundLabel.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.noneFoundLabel.Location = new System.Drawing.Point(6, 22);
this.noneFoundLabel.Dock = System.Windows.Forms.DockStyle.Fill;
this.noneFoundLabel.Location = new System.Drawing.Point(3, 19);
this.noneFoundLabel.Name = "noneFoundLabel";
this.noneFoundLabel.Size = new System.Drawing.Size(548, 280);
this.noneFoundLabel.Size = new System.Drawing.Size(554, 218);
this.noneFoundLabel.TabIndex = 1002;
this.noneFoundLabel.Text = "No CreamAPI-applicable programs were found on your computer!";
this.noneFoundLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
@ -160,8 +160,8 @@ namespace CreamInstaller
//
// selectionTreeView
//
this.selectionTreeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
this.selectionTreeView.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.selectionTreeView.BackColor = System.Drawing.SystemColors.Control;
this.selectionTreeView.BorderStyle = System.Windows.Forms.BorderStyle.None;
@ -198,24 +198,40 @@ namespace CreamInstaller
this.allCheckBox.Text = "All";
this.allCheckBox.CheckedChanged += new System.EventHandler(this.OnAllCheckBoxChanged);
//
// selectionTreeView
//
this.selectionTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
this.selectionTreeView.Location = new System.Drawing.Point(3, 19);
this.selectionTreeView.Size = new System.Drawing.Size(554, 218);
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.Enabled = false;
this.selectionTreeView.FullRowSelect = true;
this.selectionTreeView.LineColor = System.Drawing.Color.Empty;
this.selectionTreeView.Name = "selectionTreeView";
this.selectionTreeView.TabIndex = 1001;
//
// progressBar1
//
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBar1.Location = new System.Drawing.Point(12, 297);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(560, 23);
this.progressBar1.TabIndex = 9;
this.progressBar.Location = new System.Drawing.Point(12, 297);
this.progressBar.Name = "progressBar1";
this.progressBar.Size = new System.Drawing.Size(560, 23);
this.progressBar.TabIndex = 9;
//
// progressLabel
//
this.progressLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressLabel.Location = new System.Drawing.Point(12, 279);
this.progressLabel.Location = new System.Drawing.Point(12, 255);
this.progressLabel.Name = "progressLabel";
this.progressLabel.Size = new System.Drawing.Size(760, 15);
this.progressLabel.Size = new System.Drawing.Size(560, 15);
this.progressLabel.TabIndex = 10;
this.progressLabel.Text = "Loading . . .";
this.progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . 0%";
//
// scanButton
//
@ -248,15 +264,39 @@ namespace CreamInstaller
this.nodeContextMenu.Name = "nodeContextMenu";
this.nodeContextMenu.Size = new System.Drawing.Size(61, 4);
//
// progressLabelGames
//
this.progressLabelGames.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressLabelGames.Font = new System.Drawing.Font("Segoe UI", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.progressLabelGames.Location = new System.Drawing.Point(12, 270);
this.progressLabelGames.Name = "progressLabelGames";
this.progressLabelGames.Size = new System.Drawing.Size(560, 12);
this.progressLabelGames.TabIndex = 11;
this.progressLabelGames.Text = "Remaining games (2): Game 1, Game 2";
//
// progressLabelDLC
//
this.progressLabelDLCs.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressLabelDLCs.Font = new System.Drawing.Font("Segoe UI", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.progressLabelDLCs.Location = new System.Drawing.Point(12, 282);
this.progressLabelDLCs.Name = "progressLabelDLC";
this.progressLabelDLCs.Size = new System.Drawing.Size(560, 12);
this.progressLabelDLCs.TabIndex = 10004;
this.progressLabelDLCs.Text = "Remaining DLC (2): 123456, 654321";
//
// SelectForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(584, 361);
this.Controls.Add(this.progressLabelDLCs);
this.Controls.Add(this.progressLabelGames);
this.Controls.Add(this.uninstallButton);
this.Controls.Add(this.scanButton);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.progressBar1);
this.Controls.Add(this.progressBar);
this.Controls.Add(this.label1);
this.Controls.Add(this.cancelButton);
this.Controls.Add(this.installButton);
@ -285,7 +325,7 @@ namespace CreamInstaller
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.ProgressBar progressBar;
private System.Windows.Forms.Label progressLabel;
private System.Windows.Forms.CheckBox allCheckBox;
private Button scanButton;
@ -297,6 +337,8 @@ namespace CreamInstaller
private FlowLayoutPanel flowLayoutPanel2;
private Button uninstallButton;
private ContextMenuStrip nodeContextMenu;
private Label progressLabelGames;
private Label progressLabelDLCs;
}
}

View file

@ -119,6 +119,66 @@ internal partial class SelectForm : CustomForm
internal List<Task> RunningTasks = new();
private List<string> RemainingGames = new();
private void UpdateRemainingGames()
{
if (Program.Canceled) return;
progressLabelGames.Text = $"Remaining games ({RemainingGames.Count}): "
+ (RemainingGames.Any() ? string.Join(", ", RemainingGames).Replace("&", "&&") : "None");
}
private void AddToRemainingGames(string gameName)
{
if (Program.Canceled) return;
progressLabelGames.TryMethodInvoke(delegate
{
if (Program.Canceled) return;
if (!RemainingGames.Contains(gameName))
RemainingGames.Add(gameName);
UpdateRemainingGames();
});
}
private void RemoveFromRemainingGames(string gameName)
{
if (Program.Canceled) return;
progressLabelGames.TryMethodInvoke(delegate
{
if (Program.Canceled) return;
if (RemainingGames.Contains(gameName))
RemainingGames.Remove(gameName);
UpdateRemainingGames();
});
}
private List<string> RemainingDLCs = new();
private void UpdateRemainingDLCs()
{
if (Program.Canceled) return;
progressLabelDLCs.Text = $"Remaining DLCs ({RemainingDLCs.Count}): "
+ (RemainingDLCs.Any() ? string.Join(", ", RemainingDLCs).Replace("&", "&&") : "None");
}
private void AddToRemainingDLCs(string dlcId)
{
if (Program.Canceled) return;
progressLabelDLCs.TryMethodInvoke(delegate
{
if (Program.Canceled) return;
if (!RemainingDLCs.Contains(dlcId))
RemainingDLCs.Add(dlcId);
UpdateRemainingDLCs();
});
}
private void RemoveFromRemainingDLCs(string dlcId)
{
if (Program.Canceled) return;
progressLabelDLCs.TryMethodInvoke(delegate
{
if (Program.Canceled) return;
if (RemainingDLCs.Contains(dlcId))
RemainingDLCs.Remove(dlcId);
UpdateRemainingDLCs();
});
}
private async Task GetCreamApiApplicablePrograms(IProgress<int> progress)
{
if (Program.Canceled) return;
@ -132,11 +192,14 @@ internal partial class SelectForm : CustomForm
List<Tuple<int, string, string, int, string>> games = await GetGamesFromLibraryDirectory(libraryDirectory);
if (games is not null)
foreach (Tuple<int, string, string, int, string> game in games)
applicablePrograms.Add(game);
if (!applicablePrograms.Any(_game => _game.Item1 == game.Item1))
applicablePrograms.Add(game);
}
int CompleteTasks = 0;
RunningTasks.Clear();
RemainingGames.Clear();
RemainingDLCs.Clear();
foreach (Tuple<int, string, string, int, string> program in applicablePrograms)
{
int appId = program.Item1;
@ -146,15 +209,24 @@ internal partial class SelectForm : CustomForm
string directory = program.Item5;
ProgramSelection selection = ProgramSelection.FromAppId(appId);
if (Program.Canceled) return;
if (Program.BlockProtectedGames && Program.IsGameBlocked(name, directory)) continue;
if (Program.IsGameBlocked(name, directory)) continue;
RunningTasks.Add(Task.Run(async () =>
{
if (Program.Canceled) return;
AddToRemainingGames(name);
List<string> dllDirectories = await GetDllDirectoriesFromGameDirectory(directory);
if (dllDirectories is null) return;
if (dllDirectories is null)
{
RemoveFromRemainingGames(name);
return;
}
VProperty appInfo = null;
if (appId > 0) appInfo = await SteamCMD.GetAppInfo(appId, branch, buildId);
if (appId > 0 && appInfo is null) return;
if (appId > 0 && appInfo is null)
{
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled) return;
ConcurrentDictionary<int, string> dlc = new();
List<Task> dlcTasks = new();
@ -167,12 +239,18 @@ internal partial class SelectForm : CustomForm
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
AddToRemainingDLCs(id.ToString());
string dlcName = null;
VProperty dlcAppInfo = await SteamCMD.GetAppInfo(id);
if (dlcAppInfo is not null) dlcName = dlcAppInfo.Value?.GetChild("common")?.GetChild("name")?.ToString();
if (Program.Canceled) return;
if (string.IsNullOrWhiteSpace(dlcName)) return; //dlcName = "Unknown DLC";
if (string.IsNullOrWhiteSpace(dlcName))
{
RemoveFromRemainingDLCs(id.ToString());
return;
}
dlc[id] = /*$"[{id}] " +*/ dlcName;
RemoveFromRemainingDLCs(id.ToString());
progress.Report(++CompleteTasks);
});
dlcTasks.Add(task);
@ -181,9 +259,17 @@ internal partial class SelectForm : CustomForm
Thread.Sleep(10); // to reduce control & window freezing
}
}
else if (appId > 0) return;
else if (appId > 0)
{
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled) return;
if (string.IsNullOrWhiteSpace(name)) return;
if (string.IsNullOrWhiteSpace(name))
{
RemoveFromRemainingGames(name);
return;
}
selection ??= new();
selection.Usable = true;
@ -209,7 +295,7 @@ internal partial class SelectForm : CustomForm
await task;
}
if (Program.Canceled) return;
selectionTreeView.Invoke((MethodInvoker)delegate
selectionTreeView.TryMethodInvoke(delegate
{
if (Program.Canceled) return;
TreeNode programNode = TreeNodes.Find(s => s.Name == "" + appId) ?? new();
@ -238,6 +324,8 @@ internal partial class SelectForm : CustomForm
}
}
});
if (Program.Canceled) return;
RemoveFromRemainingGames(name);
progress.Report(++CompleteTasks);
}));
progress.Report(-RunningTasks.Count);
@ -265,10 +353,7 @@ internal partial class SelectForm : CustomForm
installButton.Enabled = false;
uninstallButton.Enabled = installButton.Enabled;
selectionTreeView.Enabled = false;
progressLabel.Visible = true;
progressBar1.Visible = true;
progressBar1.Value = 0;
groupBox1.Size = new(groupBox1.Size.Width, groupBox1.Size.Height - 44);
ShowProgressBar();
bool setup = true;
int maxProgress = 0;
@ -282,8 +367,8 @@ internal partial class SelectForm : CustomForm
else curProgress = _progress;
int p = Math.Max(Math.Min((int)((float)(curProgress / (float)maxProgress) * 100), 100), 0);
progressLabel.Text = setup ? $"Setting up SteamCMD . . . {p}% ({curProgress}/{maxProgress})"
: $"Gathering and caching your applicable games and their DLCs . . . {p}% ({curProgress}/{maxProgress})";
progressBar1.Value = p;
: $"Gathering and caching your applicable games and their DLCs . . . {p}%";
progressBar.Value = p;
};
iProgress.Report(-1660); // not exact, number varies
@ -309,10 +394,7 @@ internal partial class SelectForm : CustomForm
});
await GetCreamApiApplicablePrograms(iProgress);
progressBar1.Value = 100;
groupBox1.Size = new(groupBox1.Size.Width, groupBox1.Size.Height + 44);
progressLabel.Visible = false;
progressBar1.Visible = false;
HideProgressBar();
selectionTreeView.Enabled = ProgramSelection.All.Any();
allCheckBox.Enabled = selectionTreeView.Enabled;
noneFoundLabel.Visible = !selectionTreeView.Enabled;
@ -373,8 +455,39 @@ internal partial class SelectForm : CustomForm
}
}
private void ShowProgressBar()
{
progressBar.Value = 0;
progressLabelGames.Text = "Loading . . . ";
progressLabel.Visible = true;
progressLabelGames.Text = "";
progressLabelGames.Visible = true;
progressLabelDLCs.Text = "";
progressLabelDLCs.Visible = true;
progressBar.Visible = true;
groupBox1.Size = new(groupBox1.Size.Width, groupBox1.Size.Height - 3
- progressLabel.Size.Height
- progressLabelGames.Size.Height
- progressLabelDLCs.Size.Height
- progressBar.Size.Height);
}
private void HideProgressBar()
{
progressBar.Value = 100;
progressLabel.Visible = false;
progressLabelGames.Visible = false;
progressLabelDLCs.Visible = false;
progressBar.Visible = false;
groupBox1.Size = new(groupBox1.Size.Width, groupBox1.Size.Height + 3
+ progressLabel.Size.Height
+ progressLabelGames.Size.Height
+ progressLabelDLCs.Size.Height
+ progressBar.Size.Height);
}
private void OnLoad(object sender, EventArgs _)
{
HideProgressBar();
selectionTreeView.TreeViewNodeSorter = new TreeNodeSorter();
selectionTreeView.AfterCheck += OnTreeViewNodeCheckedChanged;
Dictionary<string, Image> images = new();

View file

@ -28,6 +28,7 @@ internal static class Program
internal static bool IsGameBlocked(string name, string directory)
{
if (!BlockProtectedGames) return false;
if (ProtectedGameNames.Contains(name)) return true;
if (!ProtectedGameDirectoryExceptions.Contains(name))
foreach (string path in ProtectedGameDirectories)
@ -122,6 +123,15 @@ internal static class Program
await SteamCMD.Kill();
}
internal static void TryMethodInvoke(this Control control, MethodInvoker methodInvoker)
{
try
{
control.Invoke(methodInvoker);
}
catch { }
}
private static void OnApplicationExit(object s, EventArgs e) => Cleanup();
internal static void InheritLocation(this Form form, Form fromForm)