diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj
index a3fc2dc..417c9ca 100644
--- a/CreamInstaller/CreamInstaller.csproj
+++ b/CreamInstaller/CreamInstaller.csproj
@@ -5,7 +5,7 @@
True
Resources\ini.ico
true
- 3.2.2.1
+ 3.2.2.2
Resources\ini.ico
LICENSE
2021, pointfeev (https://github.com/pointfeev)
diff --git a/CreamInstaller/SelectForm.cs b/CreamInstaller/SelectForm.cs
index 86974b6..2ee6d97 100644
--- a/CreamInstaller/SelectForm.cs
+++ b/CreamInstaller/SelectForm.cs
@@ -96,6 +96,7 @@ internal partial class SelectForm : CustomForm
progress.Report(++CompleteGameCount);
}
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();
@@ -112,7 +113,7 @@ internal partial class SelectForm : CustomForm
selection.DllDirectories = steamDllDirectories ?? await EpicLibrary.GetDllDirectoriesFromGameDirectory(selection.RootDirectory);
selection.IsSteam = steamDllDirectories is not null;
- TreeNode programNode = TreeNodes.Find(s => s.Name == selection.Id) ?? new();
+ TreeNode programNode = treeNodes.Find(s => s.Name == selection.Id) ?? new();
programNode.Name = selection.Id;
programNode.Text = selection.Name;
programNode.Checked = selection.Enabled;
@@ -129,6 +130,7 @@ 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;
@@ -136,14 +138,15 @@ internal partial class SelectForm : CustomForm
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
+ Thread.Sleep(0);
List dllDirectories = await SteamLibrary.GetDllDirectoriesFromGameDirectory(directory);
if (dllDirectories is null)
{
RemoveFromRemainingGames(name);
return;
}
- AppData appData = await SteamStore.QueryStoreAPI(appId);
- VProperty appInfo = appInfo = await SteamCMD.GetAppInfo(appId, branch, buildId);
+ AppData appData = await SteamStore.QueryStoreAPI(appId, 60);
+ VProperty appInfo = await SteamCMD.GetAppInfo(appId, branch, buildId);
if (appData is null && appInfo is null)
{
RemoveFromRemainingGames(name);
@@ -164,6 +167,7 @@ internal partial class SelectForm : CustomForm
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
+ Thread.Sleep(0);
string dlcName = null;
string dlcIcon = null;
AppData dlcAppData = await SteamStore.QueryStoreAPI(dlcAppId);
@@ -223,7 +227,8 @@ internal partial class SelectForm : CustomForm
Program.Invoke(selectionTreeView, delegate
{
if (Program.Canceled) return;
- TreeNode programNode = TreeNodes.Find(s => s.Name == appId) ?? new();
+ Thread.Sleep(0);
+ TreeNode programNode = treeNodes.Find(s => s.Name == appId) ?? new();
programNode.Name = appId;
programNode.Text = appData?.name ?? name;
programNode.Checked = selection.Enabled;
@@ -232,11 +237,12 @@ internal partial class SelectForm : CustomForm
foreach (KeyValuePair pair in dlc)
{
if (Program.Canceled || programNode is null) return;
+ Thread.Sleep(0);
string appId = pair.Key;
(DlcType type, string name, string icon) dlcApp = pair.Value;
selection.AllDlc[appId] = dlcApp;
if (allCheckBox.Checked) selection.SelectedDlc[appId] = dlcApp;
- TreeNode dlcNode = TreeNodes.Find(s => s.Name == appId) ?? new();
+ TreeNode dlcNode = treeNodes.Find(s => s.Name == appId) ?? new();
dlcNode.Name = appId;
dlcNode.Text = dlcApp.name;
dlcNode.Checked = selection.SelectedDlc.ContainsKey(appId);
@@ -258,6 +264,7 @@ 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;
@@ -265,6 +272,7 @@ internal partial class SelectForm : CustomForm
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
+ Thread.Sleep(0);
List dllDirectories = await EpicLibrary.GetDllDirectoriesFromGameDirectory(directory);
if (dllDirectories is null)
{
@@ -280,6 +288,7 @@ internal partial class SelectForm : CustomForm
foreach ((string id, string name, string product, string icon, string developer) in entitlementIds)
{
if (Program.Canceled) return;
+ Thread.Sleep(0);
AddToRemainingDLCs(id);
Task task = Task.Run(() =>
{
@@ -311,24 +320,28 @@ internal partial class SelectForm : CustomForm
selection.RootDirectory = directory;
selection.DllDirectories = dllDirectories;
foreach (KeyValuePair pair in entitlements)
+ {
+ Thread.Sleep(0);
if (pair.Value.name == selection.Name)
{
selection.ProductUrl = "https://www.epicgames.com/store/product/" + pair.Value.product;
selection.IconUrl = pair.Value.icon;
selection.Publisher = pair.Value.developer;
}
+ }
if (Program.Canceled) return;
Program.Invoke(selectionTreeView, delegate
{
if (Program.Canceled) return;
- TreeNode programNode = TreeNodes.Find(s => s.Name == @namespace) ?? new();
+ Thread.Sleep(0);
+ TreeNode programNode = treeNodes.Find(s => s.Name == @namespace) ?? new();
programNode.Name = @namespace;
programNode.Text = name;
programNode.Checked = selection.Enabled;
programNode.Remove();
selectionTreeView.Nodes.Add(programNode);
- /*TreeNode catalogItemsNode = TreeNodes.Find(s => s.Name == @namespace + "_catalogItems") ?? new();
+ /*TreeNode catalogItemsNode = treeNodes.Find(s => s.Name == @namespace + "_catalogItems") ?? new();
catalogItemsNode.Name = @namespace + "_catalogItems";
catalogItemsNode.Text = "Catalog Items";
catalogItemsNode.Checked = selection.SelectedDlc.Any(pair => pair.Value.type == DlcType.CatalogItem);
@@ -336,7 +349,7 @@ internal partial class SelectForm : CustomForm
programNode.Nodes.Add(catalogItemsNode);*/
if (entitlements.Any())
{
- /*TreeNode entitlementsNode = TreeNodes.Find(s => s.Name == @namespace + "_entitlements") ?? new();
+ /*TreeNode entitlementsNode = treeNodes.Find(s => s.Name == @namespace + "_entitlements") ?? new();
entitlementsNode.Name = @namespace + "_entitlements";
entitlementsNode.Text = "Entitlements";
entitlementsNode.Checked = selection.SelectedDlc.Any(pair => pair.Value.type == DlcType.Entitlement);
@@ -345,11 +358,12 @@ internal partial class SelectForm : CustomForm
foreach (KeyValuePair pair in entitlements)
{
if (Program.Canceled || 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);
selection.AllDlc[dlcId] = dlcApp;
if (allCheckBox.Checked) selection.SelectedDlc[dlcId] = dlcApp;
- TreeNode dlcNode = TreeNodes.Find(s => s.Name == dlcId) ?? new();
+ TreeNode dlcNode = treeNodes.Find(s => s.Name == dlcId) ?? new();
dlcNode.Name = dlcId;
dlcNode.Text = dlcApp.name;
dlcNode.Checked = selection.SelectedDlc.ContainsKey(dlcId);
@@ -413,11 +427,7 @@ internal partial class SelectForm : CustomForm
setup = false;
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
ProgramSelection.ValidateAll();
- TreeNodes.ForEach(node =>
- {
- if (node.Parent is null && ProgramSelection.FromId(node.Name) is null)
- node.Remove();
- });
+ TreeNodes.ForEach(node => node.Remove());
await GetApplicablePrograms(iProgress);
await SteamCMD.Cleanup();
diff --git a/CreamInstaller/Steam/SteamStore.cs b/CreamInstaller/Steam/SteamStore.cs
index 572dfab..987d16a 100644
--- a/CreamInstaller/Steam/SteamStore.cs
+++ b/CreamInstaller/Steam/SteamStore.cs
@@ -1,7 +1,9 @@
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
using CreamInstaller.Utility;
@@ -22,30 +24,38 @@ internal static class SteamStore
return dlcIds;
});
- internal static async Task QueryStoreAPI(string appId)
+ private static readonly ConcurrentDictionary lastQueries = new();
+ internal static async Task QueryStoreAPI(string appId, int cooldown = 10)
{
if (Program.Canceled) return null;
- string response = await HttpClientManager.EnsureGet($"https://store.steampowered.com/api/appdetails?appids={appId}");
+ Thread.Sleep(0);
string cacheFile = ProgramData.AppInfoPath + @$"\{appId}.json";
- if (response is not null)
+ DateTime now = DateTime.UtcNow;
+ if (!lastQueries.TryGetValue(appId, out DateTime lastQuery) || (now - lastQuery).TotalSeconds > cooldown)
{
- IDictionary apps = (dynamic)JsonConvert.DeserializeObject(response);
- foreach (KeyValuePair app in apps)
+ lastQueries[appId] = now;
+ string response = await HttpClientManager.EnsureGet($"https://store.steampowered.com/api/appdetails?appids={appId}");
+ if (response is not null)
{
- try
+ IDictionary apps = (dynamic)JsonConvert.DeserializeObject(response);
+ foreach (KeyValuePair app in apps)
{
- AppData data = JsonConvert.DeserializeObject(app.Value.ToString()).data;
+ Thread.Sleep(0);
try
{
- File.WriteAllText(cacheFile, JsonConvert.SerializeObject(data, Formatting.Indented));
+ AppData data = JsonConvert.DeserializeObject(app.Value.ToString()).data;
+ try
+ {
+ File.WriteAllText(cacheFile, JsonConvert.SerializeObject(data, Formatting.Indented));
+ }
+ catch { }
+ return data;
+ }
+ catch (Exception e)
+ {
+ using DialogForm dialogForm = new(null);
+ dialogForm.Show(SystemIcons.Error, "Unsuccessful deserialization of query for appid " + appId + ":\n\n" + e.ToString(), "FUCK");
}
- catch { }
- return data;
- }
- catch (Exception e)
- {
- using DialogForm dialogForm = new(null);
- dialogForm.Show(SystemIcons.Error, "Unsuccessful deserialization of query for appid " + appId + ":\n\n" + e.ToString(), "FUCK");
}
}
}