v4.7.0.0 initial

- better support for games that take dlc from other games (such as warhammer 3)
- initial framework for fixing "too many requests" issues
This commit is contained in:
pointfeev 2023-02-18 01:48:14 -05:00
parent 929c6f681f
commit 4e0f361233
7 changed files with 108 additions and 41 deletions

View file

@ -98,20 +98,27 @@ internal sealed class ContextMenuItem : ToolStripMenuItem
private static async Task TryImageIdentifierInfo(ContextMenuItem item, (string id, string iconUrl) imageIdentifierInfo, Action onFail = null) private static async Task TryImageIdentifierInfo(ContextMenuItem item, (string id, string iconUrl) imageIdentifierInfo, Action onFail = null)
=> await Task.Run(async () => => await Task.Run(async () =>
{ {
(string id, string iconUrl) = imageIdentifierInfo; try
string imageIdentifier = "Icon_" + id;
if (Images.TryGetValue(imageIdentifier, out Image image) && image is not null)
item.Image = image;
else
{ {
image = await HttpClientManager.GetImageFromUrl(iconUrl); (string id, string iconUrl) = imageIdentifierInfo;
if (image is not null) string imageIdentifier = "Icon_" + id;
{ if (Images.TryGetValue(imageIdentifier, out Image image) && image is not null)
Images[imageIdentifier] = image;
item.Image = image; item.Image = image;
}
else else
onFail?.Invoke(); {
image = await HttpClientManager.GetImageFromUrl(iconUrl);
if (image is not null)
{
Images[imageIdentifier] = image;
item.Image = image;
}
else
onFail?.Invoke();
}
}
catch
{
// ignored
} }
}); });

View file

@ -4,7 +4,7 @@
<TargetFramework>net7.0-windows</TargetFramework> <TargetFramework>net7.0-windows</TargetFramework>
<UseWindowsForms>True</UseWindowsForms> <UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Resources\ini.ico</ApplicationIcon> <ApplicationIcon>Resources\ini.ico</ApplicationIcon>
<Version>4.6.1.0</Version> <Version>4.7.0.0</Version>
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright> <Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
<Company>CreamInstaller</Company> <Company>CreamInstaller</Company>
<Product>Automatic DLC Unlocker Installer &amp; Configuration Generator</Product> <Product>Automatic DLC Unlocker Installer &amp; Configuration Generator</Product>

View file

@ -208,15 +208,17 @@ internal sealed partial class SelectForm : CustomForm
while (!Program.Canceled && steamGamesToCheck > 0); while (!Program.Canceled && steamGamesToCheck > 0);
if (Program.Canceled) if (Program.Canceled)
return; return;
string fullGameAppId = null;
string dlcName = null; string dlcName = null;
string dlcIcon = null; string dlcIcon = null;
bool onSteamStore = false; bool onSteamStore = false;
AppData dlcAppData = await SteamStore.QueryStoreAPI(dlcAppId, true); AppData dlcAppData = await SteamStore.QueryStoreAPI(dlcAppId, true);
if (dlcAppData is not null) if (dlcAppData is not null)
{ {
dlcName = dlcAppData.name; dlcName = dlcAppData.Name;
dlcIcon = dlcAppData.header_image; dlcIcon = dlcAppData.HeaderImage;
onSteamStore = true; onSteamStore = true;
fullGameAppId = dlcAppData.FullGame?.AppId;
} }
else else
{ {
@ -229,8 +231,39 @@ internal sealed partial class SelectForm : CustomForm
dlcIconStaticId ??= dlcAppInfo.Value.GetChild("common")?.GetChild("logo")?.ToString(); dlcIconStaticId ??= dlcAppInfo.Value.GetChild("common")?.GetChild("logo")?.ToString();
if (dlcIconStaticId is not null) if (dlcIconStaticId is not null)
dlcIcon = IconGrabber.SteamAppImagesPath + @$"\{dlcAppId}\{dlcIconStaticId}.jpg"; dlcIcon = IconGrabber.SteamAppImagesPath + @$"\{dlcAppId}\{dlcIconStaticId}.jpg";
fullGameAppId = dlcAppInfo.Value.GetChild("common")?.GetChild("parent")?.ToString();
} }
} }
if (fullGameAppId != null && fullGameAppId != appId)
{
string fullGameName = null;
string fullGameIcon = null;
bool fullGameOnSteamStore = false;
AppData fullGameAppData = await SteamStore.QueryStoreAPI(fullGameAppId, true);
if (fullGameAppData is not null)
{
fullGameName = fullGameAppData.Name;
fullGameIcon = fullGameAppData.HeaderImage;
fullGameOnSteamStore = true;
}
else
{
VProperty fullGameAppInfo = await SteamCMD.GetAppInfo(fullGameAppId);
if (fullGameAppInfo is not null)
{
fullGameName = fullGameAppInfo.Value.GetChild("common")?.GetChild("name")?.ToString();
string fullGameIconStaticId = fullGameAppInfo.Value.GetChild("common")?.GetChild("icon")?.ToString();
fullGameIconStaticId ??= fullGameAppInfo.Value.GetChild("common")?.GetChild("logo_small")?.ToString();
fullGameIconStaticId ??= fullGameAppInfo.Value.GetChild("common")?.GetChild("logo")?.ToString();
if (fullGameIconStaticId is not null)
dlcIcon = IconGrabber.SteamAppImagesPath + @$"\{fullGameAppId}\{fullGameIconStaticId}.jpg";
}
}
if (Program.Canceled)
return;
if (!string.IsNullOrWhiteSpace(fullGameName))
dlc[fullGameAppId] = (fullGameOnSteamStore ? DlcType.Steam : DlcType.SteamHidden, fullGameName, fullGameIcon);
}
if (Program.Canceled) if (Program.Canceled)
return; return;
if (string.IsNullOrWhiteSpace(dlcName)) if (string.IsNullOrWhiteSpace(dlcName))
@ -259,17 +292,17 @@ internal sealed partial class SelectForm : CustomForm
if (koaloaderAllCheckBox.Checked) if (koaloaderAllCheckBox.Checked)
selection.Koaloader = true; selection.Koaloader = true;
selection.Id = appId; selection.Id = appId;
selection.Name = appData?.name ?? name; selection.Name = appData?.Name ?? name;
selection.RootDirectory = gameDirectory; selection.RootDirectory = gameDirectory;
selection.ExecutableDirectories = await SteamLibrary.GetExecutableDirectories(selection.RootDirectory); selection.ExecutableDirectories = await SteamLibrary.GetExecutableDirectories(selection.RootDirectory);
selection.DllDirectories = dllDirectories; selection.DllDirectories = dllDirectories;
selection.Platform = Platform.Steam; selection.Platform = Platform.Steam;
selection.ProductUrl = "https://store.steampowered.com/app/" + appId; selection.ProductUrl = "https://store.steampowered.com/app/" + appId;
selection.IconUrl = IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("icon")}.jpg"; selection.IconUrl = IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("icon")}.jpg";
selection.SubIconUrl = appData?.header_image ?? IconGrabber.SteamAppImagesPath selection.SubIconUrl = appData?.HeaderImage ?? IconGrabber.SteamAppImagesPath
+ @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("clienticon")}.ico"; + @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("clienticon")}.ico";
selection.Publisher = appData?.publishers[0] ?? appInfo?.Value.GetChild("extended")?.GetChild("publisher")?.ToString(); selection.Publisher = appData?.Publishers[0] ?? appInfo?.Value.GetChild("extended")?.GetChild("publisher")?.ToString();
selection.WebsiteUrl = appData?.website; selection.WebsiteUrl = appData?.Website;
if (Program.Canceled) if (Program.Canceled)
return; return;
selectionTreeView.Invoke(delegate selectionTreeView.Invoke(delegate
@ -279,7 +312,7 @@ internal sealed partial class SelectForm : CustomForm
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Steam && s.Name == appId) ?? new TreeNode(); TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Steam && s.Name == appId) ?? new TreeNode();
programNode.Tag = selection.Platform; programNode.Tag = selection.Platform;
programNode.Name = appId; programNode.Name = appId;
programNode.Text = appData?.name ?? name; programNode.Text = appData?.Name ?? name;
programNode.Checked = selection.Enabled; programNode.Checked = selection.Enabled;
if (programNode.TreeView is null) if (programNode.TreeView is null)
_ = selectionTreeView.Nodes.Add(programNode); _ = selectionTreeView.Nodes.Add(programNode);

View file

@ -1,36 +1,49 @@
#pragma warning disable IDE1006 // Naming Styles using System.Collections.Generic;
#pragma warning disable CA1002 // Do not expose generic lists using Newtonsoft.Json;
#pragma warning disable CA1707 // Identifiers should not contain underscores
#pragma warning disable CA2227 // Collection properties should be read only
using System.Collections.Generic;
namespace CreamInstaller.Platforms.Steam; namespace CreamInstaller.Platforms.Steam;
public class AppFullGame
{
[JsonProperty(PropertyName = "appid")] public string AppId { get; set; }
[JsonProperty(PropertyName = "name")] public string Name { get; set; }
}
public class AppData public class AppData
{ {
public string type { get; set; } [JsonProperty(PropertyName = "type")] public string Type { get; set; }
public string name { get; set; } [JsonProperty(PropertyName = "name")] public string Name { get; set; }
public int steam_appid { get; set; } [JsonProperty(PropertyName = "steam_appid")]
public int SteamAppId { get; set; }
public List<int> dlc { get; set; } [JsonProperty(PropertyName = "fullgame")]
public AppFullGame FullGame { get; set; }
public string header_image { get; set; } [JsonProperty(PropertyName = "dlc")] public List<int> DLC { get; set; }
public string website { get; set; } [JsonProperty(PropertyName = "header_image")]
public string HeaderImage { get; set; }
public List<string> developers { get; set; } [JsonProperty(PropertyName = "website")]
public string Website { get; set; }
public List<string> publishers { get; set; } [JsonProperty(PropertyName = "developers")]
public List<string> Developers { get; set; }
public List<int> packages { get; set; } [JsonProperty(PropertyName = "publishers")]
public List<string> Publishers { get; set; }
[JsonProperty(PropertyName = "packages")]
public List<int> Packages { get; set; }
} }
public class AppDetails public class AppDetails
{ {
public bool success { get; set; } [JsonProperty(PropertyName = "success")]
public bool Success { get; set; }
public AppData data { get; set; } [JsonProperty(PropertyName = "data")] public AppData Data { get; set; }
} }

View file

@ -22,9 +22,9 @@ internal static class SteamStore
=> await Task.Run(() => => await Task.Run(() =>
{ {
List<string> dlcIds = new(); List<string> dlcIds = new();
if (appData.dlc is null) if (appData.DLC is null)
return dlcIds; return dlcIds;
dlcIds.AddRange(from appId in appData.dlc where appId > 0 select appId.ToString(CultureInfo.InvariantCulture)); dlcIds.AddRange(from appId in appData.DLC where appId > 0 select appId.ToString(CultureInfo.InvariantCulture));
return dlcIds; return dlcIds;
}); });
@ -48,8 +48,8 @@ internal static class SteamStore
AppDetails appDetails = JsonConvert.DeserializeObject<AppDetails>(app.Value.ToString()); AppDetails appDetails = JsonConvert.DeserializeObject<AppDetails>(app.Value.ToString());
if (appDetails is not null) if (appDetails is not null)
{ {
AppData data = appDetails.data; AppData data = appDetails.Data;
if (!appDetails.success) if (!appDetails.Success)
{ {
#if DEBUG #if DEBUG
DebugForm.Current.Log( DebugForm.Current.Log(

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using HtmlAgilityPack; using HtmlAgilityPack;
@ -28,6 +29,19 @@ internal static class HttpClientManager
_ = response.EnsureSuccessStatusCode(); _ = response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); return await response.Content.ReadAsStringAsync();
} }
catch (HttpRequestException e)
{
if (e.StatusCode != HttpStatusCode.TooManyRequests)
{
DebugForm.Current.Log("Get request failed to " + url + ": " + e, LogTextBox.Warning);
return null;
}
#if DEBUG
DebugForm.Current.Log("Too many requests to " + url, LogTextBox.Error);
#endif
// do something special?
return null;
}
#if DEBUG #if DEBUG
catch (Exception e) catch (Exception e)
{ {

View file

@ -17,7 +17,7 @@ internal static class ProgramData
internal static readonly string AppInfoPath = DirectoryPath + @"\appinfo"; internal static readonly string AppInfoPath = DirectoryPath + @"\appinfo";
private static readonly string AppInfoVersionPath = AppInfoPath + @"\version.txt"; private static readonly string AppInfoVersionPath = AppInfoPath + @"\version.txt";
private static readonly Version MinimumAppInfoVersion = Version.Parse("3.2.0.0"); private static readonly Version MinimumAppInfoVersion = Version.Parse("4.7.0.0");
internal static readonly string CooldownPath = DirectoryPath + @"\cooldown"; internal static readonly string CooldownPath = DirectoryPath + @"\cooldown";