first implementation of ScreamAPI support
This commit is contained in:
parent
d74d54b15e
commit
26bb1269dc
31 changed files with 1252 additions and 523 deletions
|
@ -1,62 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using HtmlAgilityPack;
|
||||
|
||||
namespace CreamInstaller.Classes;
|
||||
|
||||
internal static class HttpClientManager
|
||||
{
|
||||
private static HttpClient httpClient;
|
||||
internal static void Setup()
|
||||
{
|
||||
httpClient = new();
|
||||
httpClient.DefaultRequestHeaders.Add("user-agent", $"CreamInstaller-{Environment.MachineName}_{Environment.UserDomainName}_{Environment.UserName}");
|
||||
}
|
||||
|
||||
internal static async Task<HtmlNodeCollection> GetDocumentNodes(string url, string xpath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using HttpRequestMessage request = new(HttpMethod.Get, url);
|
||||
using HttpResponseMessage response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||
response.EnsureSuccessStatusCode();
|
||||
using Stream stream = await response.Content.ReadAsStreamAsync();
|
||||
using StreamReader reader = new(stream, Encoding.UTF8);
|
||||
HtmlDocument document = new();
|
||||
document.LoadHtml(reader.ReadToEnd());
|
||||
return document.DocumentNode.SelectNodes(xpath);
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
internal static async Task<Image> GetImageFromUrl(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new Bitmap(await httpClient.GetStreamAsync(url));
|
||||
}
|
||||
catch { }
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static async Task ParseSteamStoreDlcAppIds(int appId, List<int> dlcIds)
|
||||
{
|
||||
// currently this is only really needed to get DLC that release without changing game buildid (very rare)
|
||||
// it also finds things which aren't really connected to the game itself, and thus not needed (usually soundtracks, collections, packs, etc.)
|
||||
HtmlNodeCollection nodes = await GetDocumentNodes(
|
||||
$"https://store.steampowered.com/dlc/{appId}",
|
||||
"//div[@class='recommendation']/div/a");
|
||||
if (nodes is not null)
|
||||
foreach (HtmlNode node in nodes)
|
||||
if (int.TryParse(node.Attributes?["data-ds-appid"]?.Value, out int dlcAppId) && dlcAppId > 0 && !dlcIds.Contains(dlcAppId))
|
||||
dlcIds.Add(dlcAppId);
|
||||
}
|
||||
|
||||
internal static void Dispose() => httpClient.Dispose();
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
namespace CreamInstaller.Classes;
|
||||
|
||||
internal class ProgramSelection
|
||||
{
|
||||
internal bool Enabled = false;
|
||||
internal bool Usable = true;
|
||||
|
||||
internal int SteamAppId = 0;
|
||||
internal string Name = "Program";
|
||||
|
||||
internal string IconStaticID = null;
|
||||
internal string ClientIconStaticID = null;
|
||||
|
||||
internal string RootDirectory;
|
||||
internal List<string> SteamApiDllDirectories;
|
||||
|
||||
internal VProperty AppInfo = null;
|
||||
|
||||
internal readonly SortedList<int, (string name, string iconStaticId)> AllSteamDlc = new();
|
||||
internal readonly SortedList<int, (string name, string iconStaticId)> SelectedSteamDlc = new();
|
||||
internal readonly List<Tuple<int, string, SortedList<int, (string name, string iconStaticId)>>> ExtraSteamAppIdDlc = new();
|
||||
|
||||
internal bool AreSteamApiDllsLocked
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (string directory in SteamApiDllDirectories)
|
||||
{
|
||||
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
if (api.IsFilePathLocked()
|
||||
|| api_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| cApi.IsFilePathLocked())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Toggle(int dlcAppId, (string name, string iconStaticId) dlcApp, bool enabled)
|
||||
{
|
||||
if (enabled) SelectedSteamDlc[dlcAppId] = dlcApp;
|
||||
else SelectedSteamDlc.Remove(dlcAppId);
|
||||
}
|
||||
|
||||
internal void ToggleDlc(int dlcAppId, bool enabled)
|
||||
{
|
||||
foreach (KeyValuePair<int, (string name, string iconStaticId)> pair in AllSteamDlc)
|
||||
{
|
||||
int appId = pair.Key;
|
||||
(string name, string iconStaticId) dlcApp = pair.Value;
|
||||
if (appId == dlcAppId)
|
||||
{
|
||||
Toggle(appId, dlcApp, enabled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Enabled = SelectedSteamDlc.Any();
|
||||
}
|
||||
|
||||
internal void ToggleAllDlc(bool enabled)
|
||||
{
|
||||
if (!enabled) SelectedSteamDlc.Clear();
|
||||
else foreach (KeyValuePair<int, (string name, string iconStaticId)> pair in AllSteamDlc)
|
||||
{
|
||||
int appId = pair.Key;
|
||||
(string name, string iconStaticId) dlcApp = pair.Value;
|
||||
Toggle(appId, dlcApp, enabled);
|
||||
}
|
||||
Enabled = SelectedSteamDlc.Any();
|
||||
}
|
||||
|
||||
internal ProgramSelection() => All.Add(this);
|
||||
|
||||
internal void Validate()
|
||||
{
|
||||
if (Program.IsGameBlocked(Name, RootDirectory))
|
||||
{
|
||||
All.Remove(this);
|
||||
return;
|
||||
}
|
||||
if (!Directory.Exists(RootDirectory))
|
||||
{
|
||||
All.Remove(this);
|
||||
return;
|
||||
}
|
||||
SteamApiDllDirectories.RemoveAll(directory => !Directory.Exists(directory));
|
||||
if (!SteamApiDllDirectories.Any()) All.Remove(this);
|
||||
}
|
||||
|
||||
internal static void ValidateAll() => AllSafe.ForEach(selection => selection.Validate());
|
||||
|
||||
internal static List<ProgramSelection> All = new();
|
||||
|
||||
internal static List<ProgramSelection> AllSafe => All.ToList();
|
||||
|
||||
internal static List<ProgramSelection> AllUsable => All.FindAll(s => s.Usable);
|
||||
|
||||
internal static List<ProgramSelection> AllUsableEnabled => AllUsable.FindAll(s => s.Enabled);
|
||||
|
||||
internal static ProgramSelection FromAppId(int appId) => AllUsable.Find(s => s.SteamAppId == appId);
|
||||
|
||||
internal static (int gameAppId, (string name, string iconStaticId) app)? GetDlcFromAppId(int appId)
|
||||
{
|
||||
foreach (ProgramSelection selection in AllUsable)
|
||||
foreach (KeyValuePair<int, (string name, string iconStaticId)> pair in selection.AllSteamDlc)
|
||||
if (pair.Key == appId) return (selection.SteamAppId, pair.Value);
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -5,21 +5,21 @@
|
|||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
||||
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
|
||||
<Version>2.5.0.1</Version>
|
||||
<Version>3.0.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>
|
||||
<Description />
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageProjectUrl>https://github.com/pointfeev/CreamInstaller</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/pointfeev/CreamInstaller</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageReleaseNotes>Automatically downloads and installs CreamAPI files for programs/games.</PackageReleaseNotes>
|
||||
<PackageReleaseNotes />
|
||||
<PackageTags>steam, dlc</PackageTags>
|
||||
<AssemblyName>CreamInstaller</AssemblyName>
|
||||
<Company>CreamInstaller</Company>
|
||||
<Product>CreamAPI Generator & Installer</Product>
|
||||
<Product>CreamAPI/ScreamAPI Installer & Configuration Generator</Product>
|
||||
<Authors>pointfeev</Authors>
|
||||
<PackageId>pointfeev.creaminstaller</PackageId>
|
||||
<StartupObject>CreamInstaller.Program</StartupObject>
|
||||
|
@ -44,6 +44,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Gameloop.Vdf" Version="0.6.1" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.42" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Onova" Version="2.6.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
73
CreamInstaller/Epic/EpicLibrary.cs
Normal file
73
CreamInstaller/Epic/EpicLibrary.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace CreamInstaller.Epic;
|
||||
|
||||
internal static class EpicLibrary
|
||||
{
|
||||
private static string epicAppDataPath = null;
|
||||
internal static string EpicAppDataPath
|
||||
{
|
||||
get
|
||||
{
|
||||
epicAppDataPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Epic Games\EpicGamesLauncher", "AppDataPath", null) as string;
|
||||
epicAppDataPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Epic Games\EpicGamesLauncher", "AppDataPath", null) as string;
|
||||
return epicAppDataPath;
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task<List<Manifest>> GetGames() => await Task.Run(() =>
|
||||
{
|
||||
List<Manifest> games = new();
|
||||
if (!Directory.Exists(EpicAppDataPath)) return games;
|
||||
string manifests = EpicAppDataPath + @"\Manifests";
|
||||
if (!Directory.Exists(manifests)) return games;
|
||||
string[] files = Directory.GetFiles(manifests);
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (Program.Canceled) return games;
|
||||
if (Path.GetExtension(file) == ".item")
|
||||
{
|
||||
string json = File.ReadAllText(file);
|
||||
try
|
||||
{
|
||||
Manifest manifest = JsonSerializer.Deserialize<Manifest>(json);
|
||||
if (manifest is not null && manifest.CatalogItemId == manifest.MainGameCatalogItemId)
|
||||
games.Add(manifest);
|
||||
}
|
||||
catch { };
|
||||
}
|
||||
}
|
||||
return games;
|
||||
});
|
||||
|
||||
internal static async Task<List<string>> GetDllDirectoriesFromGameDirectory(string gameDirectory) => await Task.Run(async () =>
|
||||
{
|
||||
List<string> dllDirectories = new();
|
||||
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
|
||||
gameDirectory.GetScreamApiComponents(out string sdk, out string sdk_o, out string sdk64, out string sdk64_o, out string sApi);
|
||||
if (File.Exists(sdk)
|
||||
|| File.Exists(sdk_o)
|
||||
|| File.Exists(sdk64)
|
||||
|| File.Exists(sdk64_o)
|
||||
|| File.Exists(sApi))
|
||||
dllDirectories.Add(gameDirectory);
|
||||
string[] directories = Directory.GetDirectories(gameDirectory);
|
||||
foreach (string _directory in directories)
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
try
|
||||
{
|
||||
List<string> moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
|
||||
if (moreDllDirectories is not null) dllDirectories.AddRange(moreDllDirectories);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return !dllDirectories.Any() ? null : dllDirectories;
|
||||
});
|
||||
}
|
47
CreamInstaller/Epic/EpicStore.cs
Normal file
47
CreamInstaller/Epic/EpicStore.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
using CreamInstaller.Epic.GraphQL;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CreamInstaller.Epic;
|
||||
|
||||
internal static class EpicStore
|
||||
{
|
||||
internal static async Task<List<(string id, string name)>> ParseDlcAppIds(string categoryNamespace)
|
||||
{
|
||||
List<(string id, string name)> dlcIds = new();
|
||||
Response response = await QueryEpicGraphQL(categoryNamespace);
|
||||
if (response is null)
|
||||
return dlcIds;
|
||||
List<Element> elements = new(response.Data.Catalog.CatalogOffers.Elements);
|
||||
elements.AddRange(response.Data.Catalog.SearchStore.Elements);
|
||||
foreach (Element element in elements)
|
||||
{
|
||||
(string id, string name) app = (element.Items[0].Id, element.Title);
|
||||
if (!dlcIds.Contains(app))
|
||||
dlcIds.Add(app);
|
||||
}
|
||||
return dlcIds;
|
||||
}
|
||||
|
||||
internal static async Task<Response> QueryEpicGraphQL(string categoryNamespace)
|
||||
{
|
||||
string encoded = HttpUtility.UrlEncode(categoryNamespace);
|
||||
Request request = new(encoded);
|
||||
string payload = JsonConvert.SerializeObject(request);
|
||||
HttpContent content = new StringContent(payload);
|
||||
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
HttpClient client = HttpClientManager.HttpClient;
|
||||
if (client is null) return null;
|
||||
HttpResponseMessage httpResponse = await client.PostAsync("https://graphql.epicgames.com/graphql", content);
|
||||
httpResponse.EnsureSuccessStatusCode();
|
||||
string response = await httpResponse.Content.ReadAsStringAsync();
|
||||
return JsonConvert.DeserializeObject<Response>(response);
|
||||
}
|
||||
}
|
94
CreamInstaller/Epic/GraphQL/Request.cs
Normal file
94
CreamInstaller/Epic/GraphQL/Request.cs
Normal file
|
@ -0,0 +1,94 @@
|
|||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CreamInstaller.Epic.GraphQL;
|
||||
|
||||
internal class Request
|
||||
{
|
||||
#pragma warning disable IDE0051 // Remove unused private members
|
||||
#pragma warning disable CA1822 // Mark members as static
|
||||
#pragma warning disable IDE0052 // Remove unread private members
|
||||
#pragma warning disable IDE1006 // Naming Styles
|
||||
|
||||
[JsonProperty(PropertyName = "query")]
|
||||
private string _gqlQuery => @"query searchOffers($namespace: String!) {
|
||||
Catalog {
|
||||
catalogOffers(
|
||||
namespace: $namespace
|
||||
params: {
|
||||
count: 1000,
|
||||
}
|
||||
) {
|
||||
elements {
|
||||
id
|
||||
title
|
||||
offerType
|
||||
items {
|
||||
id
|
||||
}
|
||||
keyImages {
|
||||
type
|
||||
url
|
||||
}
|
||||
catalogNs {
|
||||
mappings(pageType: ""productHome"") {
|
||||
pageSlug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
searchStore(category: ""games/edition/base"", namespace: $namespace) {
|
||||
elements {
|
||||
id
|
||||
title
|
||||
offerType
|
||||
items {
|
||||
id
|
||||
}
|
||||
keyImages {
|
||||
type
|
||||
url
|
||||
}
|
||||
catalogNs {
|
||||
mappings(pageType: ""productHome"") {
|
||||
pageSlug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}";
|
||||
|
||||
[JsonProperty(PropertyName = "variables")]
|
||||
private Variables _variables { get; set; }
|
||||
|
||||
internal Request(string _namespace) => _variables = new Variables(_namespace);
|
||||
|
||||
private class Headers
|
||||
{
|
||||
[JsonProperty(PropertyName = "Content-Type")]
|
||||
private string _contentType => "application/graphql";
|
||||
}
|
||||
|
||||
private class Variables
|
||||
{
|
||||
[JsonProperty(PropertyName = "category")]
|
||||
private string _category => "games/edition/base|bundles/games|editors|software/edition/base";
|
||||
|
||||
[JsonProperty(PropertyName = "count")]
|
||||
private int _count => 1000;
|
||||
|
||||
[JsonProperty(PropertyName = "keywords")]
|
||||
private string _keywords => "";
|
||||
|
||||
[JsonProperty(PropertyName = "namespace")]
|
||||
private string _namespace { get; set; }
|
||||
|
||||
internal Variables(string _namespace) => this._namespace = _namespace;
|
||||
}
|
||||
|
||||
#pragma warning restore IDE0051 // Remove unused private members
|
||||
#pragma warning restore CA1822 // Mark members as static
|
||||
#pragma warning restore IDE0052 // Remove unread private members
|
||||
#pragma warning restore IDE1006 // Naming Styles
|
||||
}
|
95
CreamInstaller/Epic/GraphQL/Response.cs
Normal file
95
CreamInstaller/Epic/GraphQL/Response.cs
Normal file
|
@ -0,0 +1,95 @@
|
|||
using System;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CreamInstaller.Epic.GraphQL;
|
||||
|
||||
public class Response
|
||||
{
|
||||
[JsonProperty(PropertyName = "data")]
|
||||
public Data Data { get; protected set; }
|
||||
}
|
||||
|
||||
public class Data
|
||||
{
|
||||
[JsonProperty(PropertyName = "Catalog")]
|
||||
public Catalog Catalog { get; protected set; }
|
||||
}
|
||||
|
||||
public class Catalog
|
||||
{
|
||||
[JsonProperty(PropertyName = "catalogOffers")]
|
||||
public SearchStore CatalogOffers { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "searchStore")]
|
||||
public SearchStore SearchStore { get; protected set; }
|
||||
}
|
||||
|
||||
public class CatalogOffers
|
||||
{
|
||||
[JsonProperty(PropertyName = "namespace")]
|
||||
public string Namespace { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "params")]
|
||||
public Parameters Parameters { get; protected set; }
|
||||
}
|
||||
|
||||
public class Parameters
|
||||
{
|
||||
[JsonProperty(PropertyName = "count")]
|
||||
public int Count { get; protected set; }
|
||||
}
|
||||
|
||||
public class SearchStore
|
||||
{
|
||||
[JsonProperty(PropertyName = "elements")]
|
||||
public Element[] Elements { get; protected set; }
|
||||
}
|
||||
|
||||
public class Element
|
||||
{
|
||||
[JsonProperty(PropertyName = "id")]
|
||||
public string Id { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "title")]
|
||||
public string Title { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "offerType")]
|
||||
public string OfferType { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "items")]
|
||||
public Item[] Items { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "keyImages")]
|
||||
public KeyImage[] KeyImages { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "catalogNs")]
|
||||
public CatalogNs CatalogNs { get; protected set; }
|
||||
}
|
||||
|
||||
public class Item
|
||||
{
|
||||
[JsonProperty(PropertyName = "id")]
|
||||
public string Id { get; protected set; }
|
||||
}
|
||||
|
||||
public class KeyImage
|
||||
{
|
||||
[JsonProperty(PropertyName = "type")]
|
||||
public string Type { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "url")]
|
||||
public string Url { get; protected set; }
|
||||
}
|
||||
|
||||
public class CatalogNs
|
||||
{
|
||||
[JsonProperty(PropertyName = "mappings")]
|
||||
public Mapping[] Mappings { get; protected set; }
|
||||
}
|
||||
|
||||
public class Mapping
|
||||
{
|
||||
[JsonProperty(PropertyName = "pageSlug")]
|
||||
public string PageSlug { get; protected set; }
|
||||
}
|
53
CreamInstaller/Epic/Manifest.cs
Normal file
53
CreamInstaller/Epic/Manifest.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace CreamInstaller.Epic;
|
||||
|
||||
public class Manifest
|
||||
{
|
||||
#pragma warning disable IDE1006 // Naming Styles
|
||||
public int FormatVersion { get; set; }
|
||||
public bool bIsIncompleteInstall { get; set; }
|
||||
public string LaunchCommand { get; set; }
|
||||
public string LaunchExecutable { get; set; }
|
||||
public string ManifestLocation { get; set; }
|
||||
public bool bIsApplication { get; set; }
|
||||
public bool bIsExecutable { get; set; }
|
||||
public bool bIsManaged { get; set; }
|
||||
public bool bNeedsValidation { get; set; }
|
||||
public bool bRequiresAuth { get; set; }
|
||||
public bool bAllowMultipleInstances { get; set; }
|
||||
public bool bCanRunOffline { get; set; }
|
||||
public bool bAllowUriCmdArgs { get; set; }
|
||||
public List<string> BaseURLs { get; set; }
|
||||
public string BuildLabel { get; set; }
|
||||
public List<string> AppCategories { get; set; }
|
||||
public List<object> ChunkDbs { get; set; }
|
||||
public List<object> CompatibleApps { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string InstallationGuid { get; set; }
|
||||
public string InstallLocation { get; set; }
|
||||
public string InstallSessionId { get; set; }
|
||||
public List<object> InstallTags { get; set; }
|
||||
public List<object> InstallComponents { get; set; }
|
||||
public string HostInstallationGuid { get; set; }
|
||||
public List<string> PrereqIds { get; set; }
|
||||
public string StagingLocation { get; set; }
|
||||
public string TechnicalType { get; set; }
|
||||
public string VaultThumbnailUrl { get; set; }
|
||||
public string VaultTitleText { get; set; }
|
||||
public long InstallSize { get; set; }
|
||||
public string MainWindowProcessName { get; set; }
|
||||
public List<object> ProcessNames { get; set; }
|
||||
public List<object> BackgroundProcessNames { get; set; }
|
||||
public string MandatoryAppFolderName { get; set; }
|
||||
public string OwnershipToken { get; set; }
|
||||
public string CatalogNamespace { get; set; }
|
||||
public string CatalogItemId { get; set; }
|
||||
public string AppName { get; set; }
|
||||
public string AppVersionString { get; set; }
|
||||
public string MainGameCatalogNamespace { get; set; }
|
||||
public string MainGameCatalogItemId { get; set; }
|
||||
public string MainGameAppName { get; set; }
|
||||
public List<object> AllowedUriEnvVars { get; set; }
|
||||
#pragma warning restore IDE1006 // Naming Styles
|
||||
}
|
|
@ -34,7 +34,7 @@ internal class CustomTreeView : TreeView
|
|||
Font subFont = new(font.FontFamily, font.SizeInPoints, FontStyle.Regular, font.Unit, font.GdiCharSet, font.GdiVerticalFont);
|
||||
|
||||
string subText = node.Name;
|
||||
if (subText is null || !int.TryParse(subText, out int subInt) || subInt <= 0)
|
||||
if (subText == "ParadoxLauncher")
|
||||
return;
|
||||
|
||||
Size subSize = TextRenderer.MeasureText(graphics, subText, subFont);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Drawing;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CreamInstaller.Forms.Components;
|
||||
|
@ -9,12 +10,11 @@ internal partial class DialogForm : CustomForm
|
|||
{
|
||||
internal DialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
|
||||
|
||||
internal DialogResult Show(string formName, Icon descriptionIcon, string descriptionText, string acceptButtonText, string cancelButtonText = null, Icon customFormIcon = null)
|
||||
internal DialogResult Show(Icon descriptionIcon, string descriptionText, string acceptButtonText, string cancelButtonText = null, Icon customFormIcon = null)
|
||||
{
|
||||
if (customFormIcon is not null)
|
||||
Icon = customFormIcon;
|
||||
icon.Image = descriptionIcon.ToBitmap();
|
||||
Text = formName;
|
||||
descriptionLabel.Text = descriptionText;
|
||||
acceptButton.Text = acceptButtonText;
|
||||
if (cancelButtonText is null)
|
||||
|
@ -23,6 +23,13 @@ internal partial class DialogForm : CustomForm
|
|||
cancelButton.Visible = false;
|
||||
}
|
||||
else cancelButton.Text = cancelButtonText;
|
||||
OnResize(null, null);
|
||||
Resize += OnResize;
|
||||
return ShowDialog();
|
||||
}
|
||||
|
||||
internal void OnResize(object s, EventArgs e) =>
|
||||
Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
|
||||
? Program.ApplicationNameShort
|
||||
: Program.ApplicationName;
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CreamInstaller.Classes;
|
||||
using CreamInstaller.Forms.Components;
|
||||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller;
|
||||
|
||||
|
@ -53,9 +53,8 @@ internal partial class InstallForm : CustomForm
|
|||
}
|
||||
}
|
||||
|
||||
internal static void WriteConfiguration(StreamWriter writer, int steamAppId, string name, SortedList<int, (string name, string iconStaticId)> steamDlcApps, InstallForm installForm = null)
|
||||
internal static void WriteCreamConfiguration(StreamWriter writer, string steamAppId, string name, SortedList<string, (string name, string iconStaticId)> steamDlcApps, InstallForm installForm = null)
|
||||
{
|
||||
writer.WriteLine();
|
||||
writer.WriteLine($"; {name}");
|
||||
writer.WriteLine("[steam]");
|
||||
writer.WriteLine($"appid = {steamAppId}");
|
||||
|
@ -63,19 +62,19 @@ internal partial class InstallForm : CustomForm
|
|||
writer.WriteLine("[dlc]");
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Added game to cream_api.ini with appid {steamAppId} ({name})", InstallationLog.Resource, info: false);
|
||||
foreach (KeyValuePair<int, (string name, string iconStaticId)> pair in steamDlcApps)
|
||||
foreach (KeyValuePair<string, (string name, string iconStaticId)> pair in steamDlcApps)
|
||||
{
|
||||
int appId = pair.Key;
|
||||
(string name, string iconStaticId) dlcApp = pair.Value;
|
||||
writer.WriteLine($"{appId} = {dlcApp.name}");
|
||||
string appId = pair.Key;
|
||||
(string dlcName, _) = pair.Value;
|
||||
writer.WriteLine($"{appId} = {dlcName}");
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Added DLC to cream_api.ini with appid {appId} ({dlcApp.name})", InstallationLog.Resource, info: false);
|
||||
installForm.UpdateUser($"Added DLC to cream_api.ini with appid {appId} ({dlcName})", InstallationLog.Resource, info: false);
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task UninstallCreamAPI(string directory, InstallForm installForm = null) => await Task.Run(() =>
|
||||
{
|
||||
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
directory.GetCreamApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
if (File.Exists(api_o))
|
||||
{
|
||||
if (File.Exists(api))
|
||||
|
@ -110,7 +109,7 @@ internal partial class InstallForm : CustomForm
|
|||
|
||||
internal static async Task InstallCreamAPI(string directory, ProgramSelection selection, InstallForm installForm = null) => await Task.Run(() =>
|
||||
{
|
||||
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
directory.GetCreamApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
if (File.Exists(api) && !File.Exists(api_o))
|
||||
{
|
||||
File.Move(api, api_o);
|
||||
|
@ -136,14 +135,125 @@ internal partial class InstallForm : CustomForm
|
|||
installForm.UpdateUser($"Wrote resource to file: {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser("Generating CreamAPI for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
|
||||
installForm.UpdateUser("Generating CreamAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
|
||||
File.Create(cApi).Close();
|
||||
StreamWriter writer = new(cApi, true, Encoding.UTF8);
|
||||
writer.WriteLine("; " + Application.CompanyName + " v" + Application.ProductVersion);
|
||||
if (selection.SteamAppId > 0)
|
||||
WriteConfiguration(writer, selection.SteamAppId, selection.Name, selection.SelectedSteamDlc, installForm);
|
||||
foreach (Tuple<int, string, SortedList<int, (string name, string iconStaticId)>> extraAppDlc in selection.ExtraSteamAppIdDlc)
|
||||
WriteConfiguration(writer, extraAppDlc.Item1, extraAppDlc.Item2, extraAppDlc.Item3, installForm);
|
||||
if (selection.Id != "ParadoxLauncher")
|
||||
WriteCreamConfiguration(writer, selection.Id, selection.Name, selection.SelectedDlc, installForm);
|
||||
foreach (Tuple<string, string, SortedList<string, (string name, string iconStaticId)>> extraAppDlc in selection.ExtraDlc)
|
||||
WriteCreamConfiguration(writer, extraAppDlc.Item1, extraAppDlc.Item2, extraAppDlc.Item3, installForm);
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
});
|
||||
|
||||
internal static void WriteScreamConfiguration(StreamWriter writer, SortedList<string, (string name, string iconStaticId)> steamDlcApps, InstallForm installForm = null)
|
||||
{
|
||||
writer.WriteLine("{");
|
||||
writer.WriteLine(" \"version\": 2,");
|
||||
writer.WriteLine(" \"logging\": false,");
|
||||
writer.WriteLine(" \"eos_logging\": false,");
|
||||
writer.WriteLine(" \"block_metrics\": false,");
|
||||
writer.WriteLine(" \"catalog_items\": {");
|
||||
writer.WriteLine(" \"unlock_all\": false,");
|
||||
writer.WriteLine(" \"override\": [");
|
||||
KeyValuePair<string, (string name, string iconStaticId)> last = steamDlcApps.Last();
|
||||
foreach (KeyValuePair<string, (string name, string iconStaticId)> pair in steamDlcApps)
|
||||
{
|
||||
string id = pair.Key;
|
||||
(string name, _) = pair.Value;
|
||||
writer.WriteLine($" \"{id}\"{(pair.Equals(last) ? "" : ",")}");
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Added DLC to ScreamAPI.json with id {id} ({name})", InstallationLog.Resource, info: false);
|
||||
}
|
||||
writer.WriteLine(" ]");
|
||||
writer.WriteLine(" },");
|
||||
writer.WriteLine(" \"entitlements\": {");
|
||||
writer.WriteLine(" \"unlock_all\": false,");
|
||||
writer.WriteLine(" \"auto_inject\": false,");
|
||||
writer.WriteLine(" \"inject\": [");
|
||||
foreach (KeyValuePair<string, (string name, string iconStaticId)> pair in steamDlcApps)
|
||||
{
|
||||
string id = pair.Key;
|
||||
(string name, _) = pair.Value;
|
||||
writer.WriteLine($" \"{id}\"{(pair.Equals(last) ? "" : ",")}");
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Added DLC to ScreamAPI.json with id {id} ({name})", InstallationLog.Resource, info: false);
|
||||
}
|
||||
writer.WriteLine(" ]");
|
||||
writer.WriteLine(" }");
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
|
||||
internal static async Task UninstallScreamAPI(string directory, InstallForm installForm = null) => await Task.Run(() =>
|
||||
{
|
||||
directory.GetScreamApiComponents(out string sdk, out string sdk_o, out string sdk64, out string sdk64_o, out string sApi);
|
||||
if (File.Exists(sdk_o))
|
||||
{
|
||||
if (File.Exists(sdk))
|
||||
{
|
||||
File.Delete(sdk);
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Deleted file: {Path.GetFileName(sdk)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
File.Move(sdk_o, sdk);
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Renamed file: {Path.GetFileName(sdk_o)} -> {Path.GetFileName(sdk)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(sdk64_o))
|
||||
{
|
||||
if (File.Exists(sdk64))
|
||||
{
|
||||
File.Delete(sdk64);
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Deleted file: {Path.GetFileName(sdk64)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
File.Move(sdk64_o, sdk64);
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Renamed file: {Path.GetFileName(sdk64_o)} -> {Path.GetFileName(sdk64)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(sApi))
|
||||
{
|
||||
File.Delete(sApi);
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Deleted file: {Path.GetFileName(sApi)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
});
|
||||
|
||||
internal static async Task InstallScreamAPI(string directory, ProgramSelection selection, InstallForm installForm = null) => await Task.Run(() =>
|
||||
{
|
||||
directory.GetScreamApiComponents(out string sdk, out string sdk_o, out string sdk64, out string sdk64_o, out string sApi);
|
||||
if (File.Exists(sdk) && !File.Exists(sdk_o))
|
||||
{
|
||||
File.Move(sdk, sdk_o);
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Renamed file: {Path.GetFileName(sdk)} -> {Path.GetFileName(sdk_o)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(sdk_o))
|
||||
{
|
||||
Properties.Resources.SDK.Write(sdk);
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Wrote resource to file: {Path.GetFileName(sdk)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(sdk64) && !File.Exists(sdk64_o))
|
||||
{
|
||||
File.Move(sdk64, sdk64_o);
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Renamed file: {Path.GetFileName(sdk64)} -> {Path.GetFileName(sdk64_o)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(sdk64_o))
|
||||
{
|
||||
Properties.Resources.SDK64.Write(sdk64);
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser($"Wrote resource to file: {Path.GetFileName(sdk64)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser("Generating ScreamAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
|
||||
File.Create(sApi).Close();
|
||||
StreamWriter writer = new(sApi, true, Encoding.UTF8);
|
||||
if (selection.Id != "ParadoxLauncher")
|
||||
WriteScreamConfiguration(writer, selection.SelectedDlc, installForm);
|
||||
foreach (Tuple<string, string, SortedList<string, (string name, string iconStaticId)>> extraAppDlc in selection.ExtraDlc)
|
||||
WriteScreamConfiguration(writer, extraAppDlc.Item3, installForm);
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
});
|
||||
|
@ -151,16 +261,27 @@ internal partial class InstallForm : CustomForm
|
|||
private async Task OperateFor(ProgramSelection selection)
|
||||
{
|
||||
UpdateProgress(0);
|
||||
int count = selection.SteamApiDllDirectories.Count;
|
||||
int count = selection.DllDirectories.Count;
|
||||
int cur = 0;
|
||||
foreach (string directory in selection.SteamApiDllDirectories)
|
||||
foreach (string directory in selection.DllDirectories)
|
||||
{
|
||||
UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")} CreamAPI for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
|
||||
UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")} {(selection.IsSteam ? "CreamAPI" : "ScreamAPI")}" +
|
||||
$" {(Uninstalling ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
|
||||
if (!Program.IsProgramRunningDialog(this, selection)) throw new OperationCanceledException();
|
||||
if (Uninstalling)
|
||||
await UninstallCreamAPI(directory, this);
|
||||
if (selection.IsSteam)
|
||||
{
|
||||
if (Uninstalling)
|
||||
await UninstallCreamAPI(directory, this);
|
||||
else
|
||||
await InstallCreamAPI(directory, selection, this);
|
||||
}
|
||||
else
|
||||
await InstallCreamAPI(directory, selection, this);
|
||||
{
|
||||
if (Uninstalling)
|
||||
await UninstallScreamAPI(directory, this);
|
||||
else
|
||||
await InstallScreamAPI(directory, selection, this);
|
||||
}
|
||||
UpdateProgress(++cur / count * 100);
|
||||
}
|
||||
UpdateProgress(100);
|
||||
|
@ -208,11 +329,11 @@ internal partial class InstallForm : CustomForm
|
|||
try
|
||||
{
|
||||
await Operate();
|
||||
UpdateUser($"CreamAPI successfully {(Uninstalling ? "uninstalled" : "installed and generated")} for " + ProgramCount + " program(s).", InstallationLog.Success);
|
||||
UpdateUser($"CreamAPI/ScreamAPI successfully {(Uninstalling ? "uninstalled" : "installed and generated")} for " + ProgramCount + " program(s).", InstallationLog.Success);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
UpdateUser($"CreamAPI {(Uninstalling ? "uninstallation" : "installation and/or generation")} failed: " + exception.ToString(), InstallationLog.Error);
|
||||
UpdateUser($"CreamAPI/ScreamAPI {(Uninstalling ? "uninstallation" : "installation and/or generation")} failed: " + exception.ToString(), InstallationLog.Error);
|
||||
retryButton.Enabled = true;
|
||||
}
|
||||
userProgressBar.Value = userProgressBar.Maximum;
|
||||
|
|
|
@ -7,8 +7,8 @@ using System.Threading.Tasks;
|
|||
using System.Web;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CreamInstaller.Classes;
|
||||
using CreamInstaller.Forms.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using HtmlAgilityPack;
|
||||
|
||||
|
@ -23,7 +23,7 @@ internal partial class MainForm : CustomForm
|
|||
internal MainForm() : base()
|
||||
{
|
||||
InitializeComponent();
|
||||
Text = Program.ApplicationName;
|
||||
Text = Program.ApplicationNameShort;
|
||||
}
|
||||
|
||||
private static CancellationTokenSource cancellationTokenSource;
|
||||
|
@ -127,7 +127,7 @@ internal partial class MainForm : CustomForm
|
|||
{
|
||||
string FileName = Path.GetFileName(Program.CurrentProcessFilePath);
|
||||
if (FileName != "CreamInstaller.exe")
|
||||
if (new DialogForm(this).Show(Program.ApplicationName, SystemIcons.Warning,
|
||||
if (new DialogForm(this).Show(SystemIcons.Warning,
|
||||
"WARNING: CreamInstaller.exe was renamed!" +
|
||||
"\n\nThis will cause unwanted behavior when updating the program!",
|
||||
"Ignore", "Abort") == DialogResult.Cancel)
|
||||
|
|
2
CreamInstaller/Forms/SelectForm.Designer.cs
generated
2
CreamInstaller/Forms/SelectForm.Designer.cs
generated
|
@ -113,7 +113,7 @@ namespace CreamInstaller
|
|||
this.noneFoundLabel.Name = "noneFoundLabel";
|
||||
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.Text = "No CreamAPI-applicable or ScreamAPI-applicable programs were found on your computer!";
|
||||
this.noneFoundLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
this.noneFoundLabel.Visible = false;
|
||||
//
|
||||
|
|
|
@ -9,9 +9,12 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CreamInstaller.Classes;
|
||||
using CreamInstaller.Epic;
|
||||
using CreamInstaller.Forms.Components;
|
||||
using CreamInstaller.Paradox;
|
||||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Steam;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
|
@ -79,152 +82,256 @@ internal partial class SelectForm : CustomForm
|
|||
}
|
||||
|
||||
internal readonly List<Task> RunningTasks = new();
|
||||
private async Task GetCreamApiApplicablePrograms(IProgress<int> progress)
|
||||
private async Task GetApplicablePrograms(IProgress<int> progress)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
List<Tuple<int, string, string, int, string>> applicablePrograms = new();
|
||||
if (Directory.Exists(SteamLibrary.ParadoxLauncherInstallPath))
|
||||
applicablePrograms.Add(new(0, "Paradox Launcher", "", 0, SteamLibrary.ParadoxLauncherInstallPath));
|
||||
List<string> gameLibraryDirectories = await SteamLibrary.GetLibraryDirectories();
|
||||
foreach (string libraryDirectory in gameLibraryDirectories)
|
||||
{
|
||||
List<Tuple<int, string, string, int, string>> games = await SteamLibrary.GetGamesFromLibraryDirectory(libraryDirectory);
|
||||
if (games is not null)
|
||||
foreach (Tuple<int, string, string, int, string> game in games)
|
||||
if (!applicablePrograms.Any(_game => _game.Item1 == game.Item1))
|
||||
applicablePrograms.Add(game);
|
||||
}
|
||||
|
||||
int CompleteTasks = 0;
|
||||
RunningTasks.Clear(); // contains all running tasks including games AND their dlc
|
||||
RemainingGames.Clear(); // for display purposes only, otherwise ignorable
|
||||
RemainingDLCs.Clear(); // for display purposes only, otherwise ignorable
|
||||
List<Task> appTasks = new();
|
||||
foreach (Tuple<int, string, string, int, string> program in applicablePrograms)
|
||||
if (Directory.Exists(ParadoxLauncher.InstallPath))
|
||||
{
|
||||
int appId = program.Item1;
|
||||
string name = program.Item2;
|
||||
string branch = program.Item3;
|
||||
int buildId = program.Item4;
|
||||
string directory = program.Item5;
|
||||
ProgramSelection selection = ProgramSelection.FromAppId(appId);
|
||||
if (Program.Canceled) return;
|
||||
if (Program.IsGameBlocked(name, directory)) continue;
|
||||
AddToRemainingGames(name);
|
||||
Task task = Task.Run(async () =>
|
||||
ProgramSelection selection = ProgramSelection.FromId("ParadoxLauncher");
|
||||
selection ??= new();
|
||||
if (allCheckBox.Checked) selection.Enabled = true;
|
||||
selection.Usable = true;
|
||||
selection.Id = "ParadoxLauncher";
|
||||
selection.Name = "Paradox Launcher";
|
||||
selection.RootDirectory = ParadoxLauncher.InstallPath;
|
||||
List<string> steamDllDirectories = await SteamLibrary.GetDllDirectoriesFromGameDirectory(selection.RootDirectory);
|
||||
selection.DllDirectories = steamDllDirectories ?? await EpicLibrary.GetDllDirectoriesFromGameDirectory(selection.RootDirectory);
|
||||
selection.IsSteam = steamDllDirectories is not null;
|
||||
|
||||
TreeNode programNode = TreeNodes.Find(s => s.Name == selection.Id) ?? new();
|
||||
programNode.Name = selection.Id;
|
||||
programNode.Text = selection.Name;
|
||||
programNode.Checked = selection.Enabled;
|
||||
programNode.Remove();
|
||||
selectionTreeView.Nodes.Add(programNode);
|
||||
}
|
||||
if (Directory.Exists(SteamLibrary.InstallPath))
|
||||
{
|
||||
List<Tuple<string, string, string, int, string>> steamGames = await SteamLibrary.GetGames();
|
||||
foreach (Tuple<string, string, string, int, string> program in steamGames)
|
||||
{
|
||||
string appId = program.Item1;
|
||||
string name = program.Item2;
|
||||
string branch = program.Item3;
|
||||
int buildId = program.Item4;
|
||||
string directory = program.Item5;
|
||||
ProgramSelection selection = ProgramSelection.FromId(appId);
|
||||
if (Program.Canceled) return;
|
||||
List<string> dllDirectories = await SteamLibrary.GetDllDirectoriesFromGameDirectory(directory);
|
||||
if (dllDirectories is null)
|
||||
if (Program.IsGameBlocked(name, directory)) continue;
|
||||
AddToRemainingGames(name);
|
||||
Task task = Task.Run(async () =>
|
||||
{
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
VProperty appInfo = null;
|
||||
if (appId > 0) appInfo = await SteamCMD.GetAppInfo(appId, branch, buildId);
|
||||
if (appId > 0 && appInfo is null)
|
||||
{
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
ConcurrentDictionary<int, (string name, string iconStaticId)> dlc = new();
|
||||
List<Task> dlcTasks = new();
|
||||
List<int> dlcIds = await SteamCMD.ParseDlcAppIds(appInfo);
|
||||
await HttpClientManager.ParseSteamStoreDlcAppIds(appId, dlcIds);
|
||||
if (dlcIds.Count > 0)
|
||||
{
|
||||
foreach (int dlcAppId in dlcIds)
|
||||
if (Program.Canceled) return;
|
||||
List<string> dllDirectories = await SteamLibrary.GetDllDirectoriesFromGameDirectory(directory);
|
||||
if (dllDirectories is null)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
AddToRemainingDLCs(dlcAppId.ToString());
|
||||
Task task = Task.Run(async () =>
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
VProperty appInfo = appInfo = await SteamCMD.GetAppInfo(appId, branch, buildId);
|
||||
if (appInfo is null)
|
||||
{
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
ConcurrentDictionary<string, (string name, string iconStaticId)> dlc = new();
|
||||
List<Task> dlcTasks = new();
|
||||
List<string> dlcIds = await SteamCMD.ParseDlcAppIds(appInfo);
|
||||
await SteamStore.ParseDlcAppIds(appId, dlcIds);
|
||||
if (dlcIds.Count > 0)
|
||||
{
|
||||
foreach (string dlcAppId in dlcIds)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
string dlcName = null;
|
||||
string dlcIconStaticId = null;
|
||||
VProperty dlcAppInfo = await SteamCMD.GetAppInfo(dlcAppId);
|
||||
if (dlcAppInfo is not null)
|
||||
AddToRemainingDLCs(dlcAppId);
|
||||
Task task = Task.Run(async () =>
|
||||
{
|
||||
dlcName = dlcAppInfo.Value?.GetChild("common")?.GetChild("name")?.ToString();
|
||||
dlcIconStaticId = dlcAppInfo.Value?.GetChild("common")?.GetChild("icon")?.ToString();
|
||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo_small")?.ToString();
|
||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo")?.ToString();
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
if (!string.IsNullOrWhiteSpace(dlcName))
|
||||
dlc[dlcAppId] = (dlcName, dlcIconStaticId);
|
||||
RemoveFromRemainingDLCs(dlcAppId.ToString());
|
||||
progress.Report(++CompleteTasks);
|
||||
});
|
||||
dlcTasks.Add(task);
|
||||
RunningTasks.Add(task);
|
||||
progress.Report(-RunningTasks.Count);
|
||||
Thread.Sleep(10); // to reduce control & window freezing
|
||||
}
|
||||
}
|
||||
else if (appId > 0)
|
||||
{
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
foreach (Task task in dlcTasks)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
await task;
|
||||
}
|
||||
|
||||
selection ??= new();
|
||||
selection.Usable = true;
|
||||
selection.SteamAppId = appId;
|
||||
selection.Name = name;
|
||||
selection.RootDirectory = directory;
|
||||
selection.SteamApiDllDirectories = dllDirectories;
|
||||
selection.AppInfo = appInfo;
|
||||
selection.IconStaticID = appInfo?.Value?.GetChild("common")?.GetChild("icon")?.ToString();
|
||||
selection.ClientIconStaticID = appInfo?.Value?.GetChild("common")?.GetChild("clienticon")?.ToString();
|
||||
if (allCheckBox.Checked) selection.Enabled = true;
|
||||
|
||||
if (Program.Canceled) return;
|
||||
Program.Invoke(selectionTreeView, delegate
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
TreeNode programNode = TreeNodes.Find(s => s.Name == "" + appId) ?? new();
|
||||
programNode.Name = "" + appId;
|
||||
programNode.Text = /*(appId > 0 ? $"[{appId}] " : "") +*/ name;
|
||||
programNode.Checked = selection.Enabled;
|
||||
programNode.Remove();
|
||||
selectionTreeView.Nodes.Add(programNode);
|
||||
if (appId == 0) // paradox launcher
|
||||
{
|
||||
// maybe add game and/or dlc choice here?
|
||||
if (Program.Canceled) return;
|
||||
string dlcName = null;
|
||||
string dlcIconStaticId = null;
|
||||
VProperty dlcAppInfo = await SteamCMD.GetAppInfo(dlcAppId);
|
||||
if (dlcAppInfo is not null)
|
||||
{
|
||||
dlcName = dlcAppInfo.Value?.GetChild("common")?.GetChild("name")?.ToString();
|
||||
dlcIconStaticId = dlcAppInfo.Value?.GetChild("common")?.GetChild("icon")?.ToString();
|
||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo_small")?.ToString();
|
||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo")?.ToString();
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
if (!string.IsNullOrWhiteSpace(dlcName))
|
||||
dlc[dlcAppId] = (dlcName, dlcIconStaticId);
|
||||
RemoveFromRemainingDLCs(dlcAppId);
|
||||
progress.Report(++CompleteTasks);
|
||||
});
|
||||
dlcTasks.Add(task);
|
||||
RunningTasks.Add(task);
|
||||
progress.Report(-RunningTasks.Count);
|
||||
Thread.Sleep(10); // to reduce control & window freezing
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (KeyValuePair<int, (string name, string iconStaticId)> pair in dlc)
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
foreach (Task task in dlcTasks)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
await task;
|
||||
}
|
||||
|
||||
selection ??= new();
|
||||
if (allCheckBox.Checked) selection.Enabled = true;
|
||||
selection.Usable = true;
|
||||
selection.Id = appId;
|
||||
selection.Name = name;
|
||||
selection.RootDirectory = directory;
|
||||
selection.DllDirectories = dllDirectories;
|
||||
selection.IsSteam = true;
|
||||
selection.AppInfo = appInfo;
|
||||
selection.IconStaticID = appInfo?.Value?.GetChild("common")?.GetChild("icon")?.ToString();
|
||||
selection.ClientIconStaticID = appInfo?.Value?.GetChild("common")?.GetChild("clienticon")?.ToString();
|
||||
|
||||
if (Program.Canceled) return;
|
||||
Program.Invoke(selectionTreeView, delegate
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
TreeNode programNode = TreeNodes.Find(s => s.Name == appId) ?? new();
|
||||
programNode.Name = appId;
|
||||
programNode.Text = name;
|
||||
programNode.Checked = selection.Enabled;
|
||||
programNode.Remove();
|
||||
selectionTreeView.Nodes.Add(programNode);
|
||||
foreach (KeyValuePair<string, (string name, string iconStaticId)> pair in dlc)
|
||||
{
|
||||
if (Program.Canceled || programNode is null) return;
|
||||
int appId = pair.Key;
|
||||
string appId = pair.Key;
|
||||
(string name, string iconStaticId) dlcApp = pair.Value;
|
||||
selection.AllSteamDlc[appId] = dlcApp;
|
||||
if (allCheckBox.Checked) selection.SelectedSteamDlc[appId] = dlcApp;
|
||||
TreeNode dlcNode = TreeNodes.Find(s => s.Name == "" + appId) ?? new();
|
||||
dlcNode.Name = appId.ToString();
|
||||
selection.AllDlc[appId] = dlcApp;
|
||||
if (allCheckBox.Checked) selection.SelectedDlc[appId] = dlcApp;
|
||||
TreeNode dlcNode = TreeNodes.Find(s => s.Name == appId) ?? new();
|
||||
dlcNode.Name = appId;
|
||||
dlcNode.Text = dlcApp.name;
|
||||
dlcNode.Checked = selection.SelectedSteamDlc.ContainsKey(appId);
|
||||
dlcNode.Checked = selection.SelectedDlc.ContainsKey(appId);
|
||||
dlcNode.Remove();
|
||||
programNode.Nodes.Add(dlcNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (Program.Canceled) return;
|
||||
RemoveFromRemainingGames(name);
|
||||
progress.Report(++CompleteTasks);
|
||||
});
|
||||
appTasks.Add(task);
|
||||
RunningTasks.Add(task);
|
||||
progress.Report(-RunningTasks.Count);
|
||||
}
|
||||
}
|
||||
if (Directory.Exists(EpicLibrary.EpicAppDataPath))
|
||||
{
|
||||
List<Manifest> epicGames = await EpicLibrary.GetGames();
|
||||
Dictionary<string, List<string>> games = new();
|
||||
foreach (Manifest manifest in epicGames)
|
||||
{
|
||||
string id = manifest.CatalogNamespace;
|
||||
string name = manifest.DisplayName;
|
||||
string directory = manifest.InstallLocation;
|
||||
ProgramSelection selection = ProgramSelection.FromId(id);
|
||||
if (Program.Canceled) return;
|
||||
RemoveFromRemainingGames(name);
|
||||
progress.Report(++CompleteTasks);
|
||||
});
|
||||
appTasks.Add(task);
|
||||
RunningTasks.Add(task);
|
||||
progress.Report(-RunningTasks.Count);
|
||||
if (Program.IsGameBlocked(name, directory)) continue;
|
||||
AddToRemainingGames(name);
|
||||
Task task = Task.Run(async () =>
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
List<string> dllDirectories = await EpicLibrary.GetDllDirectoriesFromGameDirectory(directory);
|
||||
if (dllDirectories is null)
|
||||
{
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
ConcurrentDictionary<string, string> dlc = new();
|
||||
List<Task> dlcTasks = new();
|
||||
List<(string id, string name)> dlcIds = await EpicStore.ParseDlcAppIds(id);
|
||||
if (dlcIds.Count > 0)
|
||||
{
|
||||
foreach ((string id, string name) in dlcIds)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
AddToRemainingDLCs(id);
|
||||
Task task = Task.Run(() =>
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
dlc[id] = name;
|
||||
RemoveFromRemainingDLCs(id);
|
||||
progress.Report(++CompleteTasks);
|
||||
});
|
||||
dlcTasks.Add(task);
|
||||
RunningTasks.Add(task);
|
||||
progress.Report(-RunningTasks.Count);
|
||||
Thread.Sleep(10); // to reduce control & window freezing
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
foreach (Task task in dlcTasks)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
await task;
|
||||
}
|
||||
|
||||
selection ??= new();
|
||||
if (allCheckBox.Checked) selection.Enabled = true;
|
||||
selection.Usable = true;
|
||||
selection.Id = id;
|
||||
selection.Name = name;
|
||||
selection.RootDirectory = directory;
|
||||
selection.DllDirectories = dllDirectories;
|
||||
|
||||
if (Program.Canceled) return;
|
||||
Program.Invoke(selectionTreeView, delegate
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
TreeNode programNode = TreeNodes.Find(s => s.Name == id) ?? new();
|
||||
programNode.Name = id;
|
||||
programNode.Text = name;
|
||||
programNode.Checked = selection.Enabled;
|
||||
programNode.Remove();
|
||||
selectionTreeView.Nodes.Add(programNode);
|
||||
foreach (KeyValuePair<string, string> pair in dlc)
|
||||
{
|
||||
if (Program.Canceled || programNode is null) return;
|
||||
string dlcId = pair.Key;
|
||||
string dlcName = pair.Value;
|
||||
(string name, string iconStaticId) dlcApp = (dlcName, null); // temporary?
|
||||
selection.AllDlc[dlcId] = dlcApp;
|
||||
if (allCheckBox.Checked) selection.SelectedDlc[dlcId] = dlcApp;
|
||||
TreeNode dlcNode = TreeNodes.Find(s => s.Name == dlcId) ?? new();
|
||||
dlcNode.Name = dlcId;
|
||||
dlcNode.Text = dlcName;
|
||||
dlcNode.Checked = selection.SelectedDlc.ContainsKey(dlcId);
|
||||
dlcNode.Remove();
|
||||
programNode.Nodes.Add(dlcNode);
|
||||
}
|
||||
});
|
||||
if (Program.Canceled) return;
|
||||
RemoveFromRemainingGames(name);
|
||||
progress.Report(++CompleteTasks);
|
||||
});
|
||||
appTasks.Add(task);
|
||||
RunningTasks.Add(task);
|
||||
progress.Report(-RunningTasks.Count);
|
||||
}
|
||||
}
|
||||
foreach (Task task in appTasks)
|
||||
{
|
||||
|
@ -267,17 +374,19 @@ internal partial class SelectForm : CustomForm
|
|||
progressBar.Value = p;
|
||||
};
|
||||
|
||||
progressLabel.Text = $"Setting up SteamCMD . . . ";
|
||||
await SteamCMD.Setup(iProgress);
|
||||
|
||||
if (Directory.Exists(SteamLibrary.InstallPath))
|
||||
{
|
||||
progressLabel.Text = $"Setting up SteamCMD . . . ";
|
||||
await SteamCMD.Setup(iProgress);
|
||||
}
|
||||
setup = false;
|
||||
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
|
||||
ProgramSelection.ValidateAll();
|
||||
TreeNodes.ForEach(node =>
|
||||
{
|
||||
if (!int.TryParse(node.Name, out int appId) || node.Parent is null && ProgramSelection.FromAppId(appId) is null) node.Remove();
|
||||
if (!int.TryParse(node.Name, out int appId) || node.Parent is null && ProgramSelection.FromId(node.Name) is null) node.Remove();
|
||||
});
|
||||
await GetCreamApiApplicablePrograms(iProgress);
|
||||
await GetApplicablePrograms(iProgress);
|
||||
await SteamCMD.Cleanup();
|
||||
|
||||
HideProgressBar();
|
||||
|
@ -302,21 +411,23 @@ internal partial class SelectForm : CustomForm
|
|||
{
|
||||
if (e.Action == TreeViewAction.Unknown) return;
|
||||
TreeNode node = e.Node;
|
||||
if (node is not null && int.TryParse(node.Name, out int appId))
|
||||
if (node is not null)
|
||||
{
|
||||
ProgramSelection selection = ProgramSelection.FromAppId(appId);
|
||||
string appId = node.Name;
|
||||
ProgramSelection selection = ProgramSelection.FromId(appId);
|
||||
if (selection is null)
|
||||
{
|
||||
TreeNode parent = node.Parent;
|
||||
if (parent is not null && int.TryParse(parent.Name, out int gameAppId))
|
||||
if (parent is not null)
|
||||
{
|
||||
ProgramSelection.FromAppId(gameAppId).ToggleDlc(appId, node.Checked);
|
||||
string gameAppId = parent.Name;
|
||||
ProgramSelection.FromId(gameAppId).ToggleDlc(appId, node.Checked);
|
||||
parent.Checked = parent.Nodes.Cast<TreeNode>().ToList().Any(treeNode => treeNode.Checked);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selection.AllSteamDlc.Any())
|
||||
if (selection.AllDlc.Any())
|
||||
{
|
||||
selection.ToggleAllDlc(node.Checked);
|
||||
node.Nodes.Cast<TreeNode>().ToList().ForEach(treeNode => treeNode.Checked = node.Checked);
|
||||
|
@ -345,10 +456,19 @@ internal partial class SelectForm : CustomForm
|
|||
|
||||
private class TreeNodeSorter : IComparer
|
||||
{
|
||||
public int Compare(object a, object b) =>
|
||||
!int.TryParse((a as TreeNode).Name, out int A) ? 1
|
||||
: !int.TryParse((b as TreeNode).Name, out int B) ? 0
|
||||
: A > B ? 1 : 0;
|
||||
public int Compare(object a, object b)
|
||||
{
|
||||
string aId = (a as TreeNode).Name;
|
||||
string bId = (b as TreeNode).Name;
|
||||
return aId == "ParadoxLauncher" ? -1
|
||||
: bId == "ParadoxLauncher" ? 1
|
||||
: !int.TryParse(aId, out _) && !int.TryParse(bId, out _) ? string.Compare(aId, bId)
|
||||
: !int.TryParse(aId, out int A) ? 1
|
||||
: !int.TryParse(bId, out int B) ? -1
|
||||
: A > B ? 1
|
||||
: A < B ? -1
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowProgressBar()
|
||||
|
@ -389,11 +509,11 @@ internal partial class SelectForm : CustomForm
|
|||
Dictionary<string, Image> images = new();
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (Directory.Exists(SteamLibrary.ParadoxLauncherInstallPath))
|
||||
if (Directory.Exists(ParadoxLauncher.InstallPath))
|
||||
{
|
||||
foreach (string file in Directory.GetFiles(SteamLibrary.ParadoxLauncherInstallPath, "*.exe"))
|
||||
foreach (string file in Directory.GetFiles(ParadoxLauncher.InstallPath, "*.exe"))
|
||||
{
|
||||
images["Paradox Launcher"] = IconGrabber.GetFileIconImage(file);
|
||||
images["Icon_ParadoxLauncher"] = IconGrabber.GetFileIconImage(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -405,7 +525,7 @@ internal partial class SelectForm : CustomForm
|
|||
images["Steam Community"] = await HttpClientManager.GetImageFromUrl("https://steamcommunity.com/favicon.ico");
|
||||
});
|
||||
Image Image(string identifier) => images.GetValueOrDefault(identifier, null);
|
||||
void TrySetImageAsync(ToolStripMenuItem menuItem, int appId, string iconStaticId, bool client = false) =>
|
||||
void TrySetImageAsync(ToolStripMenuItem menuItem, string appId, string iconStaticId, bool client = false) =>
|
||||
Task.Run(async () =>
|
||||
{
|
||||
menuItem.Image = client ? await IconGrabber.GetSteamClientIcon(appId, iconStaticId) : await IconGrabber.GetSteamIcon(appId, iconStaticId);
|
||||
|
@ -415,33 +535,33 @@ internal partial class SelectForm : CustomForm
|
|||
{
|
||||
TreeNode node = e.Node;
|
||||
TreeNode parentNode = node.Parent;
|
||||
if (!int.TryParse(node.Name, out int appId)) return;
|
||||
ProgramSelection selection = ProgramSelection.FromAppId(appId);
|
||||
(int gameAppId, (string name, string iconStaticId) app)? dlc = null;
|
||||
if (selection is null) dlc = ProgramSelection.GetDlcFromAppId(appId);
|
||||
string id = node.Name;
|
||||
ProgramSelection selection = ProgramSelection.FromId(id);
|
||||
(string gameAppId, (string name, string iconStaticId) app)? dlc = null;
|
||||
if (selection is null) dlc = ProgramSelection.GetDlcFromId(id);
|
||||
if (e.Button == MouseButtons.Right && node.Bounds.Contains(e.Location))
|
||||
{
|
||||
selectionTreeView.SelectedNode = node;
|
||||
nodeContextMenu.Items.Clear();
|
||||
ToolStripMenuItem header = new(selection?.Name ?? node.Text, Image(appId == 0 ? "Paradox Launcher" : "Icon_" + node.Name));
|
||||
ToolStripMenuItem header = new(selection?.Name ?? node.Text, Image("Icon_" + id));
|
||||
if (header.Image is null)
|
||||
{
|
||||
string iconStaticId = dlc?.app.iconStaticId ?? selection?.IconStaticID;
|
||||
if (iconStaticId is not null)
|
||||
TrySetImageAsync(header, appId, iconStaticId);
|
||||
TrySetImageAsync(header, id, iconStaticId);
|
||||
else if (dlc is not null)
|
||||
{
|
||||
int gameAppId = dlc.Value.gameAppId;
|
||||
string gameAppId = dlc.Value.gameAppId;
|
||||
header.Image = Image("Icon_" + gameAppId);
|
||||
ProgramSelection gameSelection = ProgramSelection.FromAppId(gameAppId);
|
||||
ProgramSelection gameSelection = ProgramSelection.FromId(gameAppId);
|
||||
iconStaticId = gameSelection?.IconStaticID;
|
||||
if (header.Image is null && iconStaticId is not null)
|
||||
TrySetImageAsync(header, gameAppId, iconStaticId);
|
||||
}
|
||||
}
|
||||
nodeContextMenu.Items.Add(header);
|
||||
string appInfo = $@"{SteamCMD.AppInfoPath}\{appId}.vdf";
|
||||
if (appId != 0 && Directory.Exists(Directory.GetDirectoryRoot(appInfo)) && File.Exists(appInfo))
|
||||
string appInfo = $@"{SteamCMD.AppInfoPath}\{id}.vdf";
|
||||
if (Directory.Exists(Directory.GetDirectoryRoot(appInfo)) && File.Exists(appInfo))
|
||||
{
|
||||
nodeContextMenu.Items.Add(new ToolStripSeparator());
|
||||
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open AppInfo", Image("Notepad"),
|
||||
|
@ -459,39 +579,54 @@ internal partial class SelectForm : CustomForm
|
|||
}
|
||||
if (selection is not null)
|
||||
{
|
||||
if (appId == 0)
|
||||
if (id == "ParadoxLauncher")
|
||||
{
|
||||
nodeContextMenu.Items.Add(new ToolStripSeparator());
|
||||
nodeContextMenu.Items.Add(new ToolStripMenuItem("Repair", Image("Command Prompt"),
|
||||
new EventHandler(async (sender, e) =>
|
||||
{
|
||||
if (!Program.IsProgramRunningDialog(this, selection)) return;
|
||||
|
||||
byte[] cApiIni = null;
|
||||
byte[] properApi = null;
|
||||
byte[] properApi64 = null;
|
||||
foreach (string directory in selection.SteamApiDllDirectories)
|
||||
|
||||
byte[] sApiJson = null;
|
||||
byte[] properSdk = null;
|
||||
byte[] properSdk64 = null;
|
||||
|
||||
foreach (string directory in selection.DllDirectories)
|
||||
{
|
||||
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
directory.GetCreamApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
if (cApiIni is null && File.Exists(cApi))
|
||||
cApiIni = File.ReadAllBytes(cApi);
|
||||
await InstallForm.UninstallCreamAPI(directory);
|
||||
if (properApi is null && File.Exists(api) && !FileResourceExtensions.Equals(Properties.Resources.API, api))
|
||||
if (properApi is null && File.Exists(api) && !Properties.Resources.API.EqualsFile(api))
|
||||
properApi = File.ReadAllBytes(api);
|
||||
if (properApi64 is null && File.Exists(api64) && !FileResourceExtensions.Equals(Properties.Resources.API64, api64))
|
||||
if (properApi64 is null && File.Exists(api64) && !Properties.Resources.API64.EqualsFile(api64))
|
||||
properApi64 = File.ReadAllBytes(api64);
|
||||
|
||||
directory.GetScreamApiComponents(out string sdk, out string sdk_o, out string sdk64, out string sdk64_o, out string sApi);
|
||||
if (sApiJson is null && File.Exists(sApi))
|
||||
sApiJson = File.ReadAllBytes(sApi);
|
||||
await InstallForm.UninstallCreamAPI(directory);
|
||||
if (properSdk is null && File.Exists(sdk) && !Properties.Resources.SDK.EqualsFile(sdk))
|
||||
properSdk = File.ReadAllBytes(sdk);
|
||||
if (properSdk64 is null && File.Exists(sdk64) && !Properties.Resources.SDK64.EqualsFile(sdk64))
|
||||
properSdk64 = File.ReadAllBytes(sdk64);
|
||||
}
|
||||
if (properApi is not null || properApi64 is not null)
|
||||
if (properApi is not null || properApi64 is not null || properSdk is not null || properSdk64 is not null)
|
||||
{
|
||||
bool neededRepair = false;
|
||||
foreach (string directory in selection.SteamApiDllDirectories)
|
||||
foreach (string directory in selection.DllDirectories)
|
||||
{
|
||||
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
if (properApi is not null && FileResourceExtensions.Equals(Properties.Resources.API, api))
|
||||
directory.GetCreamApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
if (properApi is not null && Properties.Resources.API.EqualsFile(api))
|
||||
{
|
||||
properApi.Write(api);
|
||||
neededRepair = true;
|
||||
}
|
||||
if (properApi64 is not null && FileResourceExtensions.Equals(Properties.Resources.API64, api64))
|
||||
if (properApi64 is not null && Properties.Resources.API64.EqualsFile(api64))
|
||||
{
|
||||
properApi64.Write(api64);
|
||||
neededRepair = true;
|
||||
|
@ -501,46 +636,67 @@ internal partial class SelectForm : CustomForm
|
|||
await InstallForm.InstallCreamAPI(directory, selection);
|
||||
cApiIni.Write(cApi);
|
||||
}
|
||||
|
||||
directory.GetScreamApiComponents(out string sdk, out string sdk_o, out string sdk64, out string sdk64_o, out string sApi);
|
||||
if (properSdk is not null && Properties.Resources.SDK.EqualsFile(sdk))
|
||||
{
|
||||
properSdk.Write(sdk);
|
||||
neededRepair = true;
|
||||
}
|
||||
if (properSdk64 is not null && Properties.Resources.SDK64.EqualsFile(sdk64))
|
||||
{
|
||||
properSdk64.Write(sdk64);
|
||||
neededRepair = true;
|
||||
}
|
||||
if (sApiJson is not null)
|
||||
{
|
||||
await InstallForm.InstallScreamAPI(directory, selection);
|
||||
sApiJson.Write(sApi);
|
||||
}
|
||||
}
|
||||
if (neededRepair)
|
||||
new DialogForm(this).Show("Paradox Launcher Repair", Icon, "Paradox Launcher successfully repaired!", "OK");
|
||||
new DialogForm(this).Show(Icon, "Paradox Launcher successfully repaired!", "OK");
|
||||
else
|
||||
new DialogForm(this).Show("Paradox Launcher Repair", SystemIcons.Information, "Paradox Launcher does not need to be repaired.", "OK");
|
||||
new DialogForm(this).Show(SystemIcons.Information, "Paradox Launcher does not need to be repaired.", "OK");
|
||||
}
|
||||
else
|
||||
new DialogForm(this).Show("Paradox Launcher Repair", SystemIcons.Error, "Paradox Launcher repair failed!"
|
||||
+ "\n\nAn original Steamworks API file could not be found."
|
||||
new DialogForm(this).Show(SystemIcons.Error, "Paradox Launcher repair failed!"
|
||||
+ "\n\nAn original Steamworks API or EOS SDK file could not be found."
|
||||
+ "\nYou must reinstall Paradox Launcher to fix this issue.", "OK");
|
||||
})));
|
||||
}
|
||||
nodeContextMenu.Items.Add(new ToolStripSeparator());
|
||||
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open Root Directory", Image("File Explorer"),
|
||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(selection.RootDirectory))));
|
||||
for (int i = 0; i < selection.SteamApiDllDirectories.Count; i++)
|
||||
for (int i = 0; i < selection.DllDirectories.Count; i++)
|
||||
{
|
||||
string directory = selection.SteamApiDllDirectories[i];
|
||||
nodeContextMenu.Items.Add(new ToolStripMenuItem($"Open Steamworks Directory ({i + 1})", Image("File Explorer"),
|
||||
string directory = selection.DllDirectories[i];
|
||||
nodeContextMenu.Items.Add(new ToolStripMenuItem($"Open {(selection.IsSteam ? "Steamworks API" : "EOS SDK")} Directory ({i + 1})", Image("File Explorer"),
|
||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
||||
}
|
||||
}
|
||||
if (appId != 0)
|
||||
if (id != "ParadoxLauncher" && selection is not null)
|
||||
{
|
||||
nodeContextMenu.Items.Add(new ToolStripSeparator());
|
||||
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open SteamDB", Image("SteamDB"),
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://steamdb.info/app/" + appId))));
|
||||
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open Steam Store", Image("Steam Store"),
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://store.steampowered.com/app/" + appId))));
|
||||
if (selection is not null)
|
||||
if (selection.IsSteam)
|
||||
{
|
||||
ToolStripMenuItem steamCommunity = new("Open Steam Community", Image("ClientIcon_" + node.Name),
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://steamcommunity.com/app/" + appId)));
|
||||
nodeContextMenu.Items.Add(new ToolStripSeparator());
|
||||
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open SteamDB", Image("SteamDB"),
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://steamdb.info/app/" + id))));
|
||||
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open Steam Store", Image("Steam Store"),
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://store.steampowered.com/app/" + id))));
|
||||
ToolStripMenuItem steamCommunity = new("Open Steam Community", Image("ClientIcon_" + id),
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://steamcommunity.com/app/" + id)));
|
||||
nodeContextMenu.Items.Add(steamCommunity);
|
||||
if (steamCommunity.Image is null)
|
||||
{
|
||||
steamCommunity.Image = Image("Steam Community");
|
||||
TrySetImageAsync(steamCommunity, appId, selection.ClientIconStaticID, true);
|
||||
TrySetImageAsync(steamCommunity, id, selection.ClientIconStaticID, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Epic Games links?
|
||||
}
|
||||
}
|
||||
nodeContextMenu.Show(selectionTreeView, e.Location);
|
||||
}
|
||||
|
@ -548,52 +704,13 @@ internal partial class SelectForm : CustomForm
|
|||
OnLoad();
|
||||
}
|
||||
|
||||
private static void PopulateParadoxLauncherDlc(ProgramSelection paradoxLauncher = null)
|
||||
{
|
||||
paradoxLauncher ??= ProgramSelection.FromAppId(0);
|
||||
if (paradoxLauncher is not null)
|
||||
{
|
||||
paradoxLauncher.ExtraSteamAppIdDlc.Clear();
|
||||
foreach (ProgramSelection selection in ProgramSelection.AllUsableEnabled)
|
||||
{
|
||||
if (selection.Name == paradoxLauncher.Name) continue;
|
||||
if (selection.AppInfo.Value?.GetChild("extended")?.GetChild("publisher")?.ToString() != "Paradox Interactive") continue;
|
||||
paradoxLauncher.ExtraSteamAppIdDlc.Add(new(selection.SteamAppId, selection.Name, selection.SelectedSteamDlc));
|
||||
}
|
||||
if (!paradoxLauncher.ExtraSteamAppIdDlc.Any())
|
||||
foreach (ProgramSelection selection in ProgramSelection.AllUsable)
|
||||
{
|
||||
if (selection.Name == paradoxLauncher.Name) continue;
|
||||
if (selection.AppInfo.Value?.GetChild("extended")?.GetChild("publisher")?.ToString() != "Paradox Interactive") continue;
|
||||
paradoxLauncher.ExtraSteamAppIdDlc.Add(new(selection.SteamAppId, selection.Name, selection.AllSteamDlc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ParadoxLauncherDlcDialog(Form form)
|
||||
{
|
||||
ProgramSelection paradoxLauncher = ProgramSelection.FromAppId(0);
|
||||
if (paradoxLauncher is not null && paradoxLauncher.Enabled)
|
||||
{
|
||||
PopulateParadoxLauncherDlc(paradoxLauncher);
|
||||
if (!paradoxLauncher.ExtraSteamAppIdDlc.Any())
|
||||
{
|
||||
return new DialogForm(form).Show(Program.ApplicationName, SystemIcons.Warning,
|
||||
$"WARNING: There are no installed games with DLC that can be added to the Paradox Launcher!" +
|
||||
"\n\nInstalling CreamAPI for the Paradox Launcher is pointless, since no DLC will be added to the configuration!",
|
||||
"Ignore", "Cancel") != DialogResult.OK;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnAccept(bool uninstall = false)
|
||||
{
|
||||
if (ProgramSelection.All.Any())
|
||||
{
|
||||
foreach (ProgramSelection selection in ProgramSelection.AllUsableEnabled)
|
||||
if (!Program.IsProgramRunningDialog(this, selection)) return;
|
||||
if (ParadoxLauncherDlcDialog(this)) return;
|
||||
if (ParadoxLauncher.DlcDialog(this)) return;
|
||||
Hide();
|
||||
InstallForm installForm = new(this, uninstall);
|
||||
installForm.ShowDialog();
|
||||
|
@ -655,9 +772,9 @@ internal partial class SelectForm : CustomForm
|
|||
string blockedDirectoryExceptions = "";
|
||||
foreach (string name in Program.ProtectedGameDirectoryExceptions)
|
||||
blockedDirectoryExceptions += helpButtonListPrefix + name;
|
||||
new DialogForm(this).Show(blockedGamesCheckBox.Text, SystemIcons.Information,
|
||||
new DialogForm(this).Show(SystemIcons.Information,
|
||||
"Blocks the program from caching and displaying games protected by DLL checks," +
|
||||
"\nanti-cheats, or that are confirmed not to be working with CreamAPI." +
|
||||
"\nanti-cheats, or that are confirmed not to be working with CreamAPI or ScreamAPI." +
|
||||
"\n\nBlocked game names:" + blockedGames +
|
||||
"\n\nBlocked game sub-directories:" + blockedDirectories +
|
||||
"\n\nBlocked game sub-directory exceptions (not blocked):" + blockedDirectoryExceptions,
|
||||
|
|
62
CreamInstaller/Paradox/ParadoxLauncher.cs
Normal file
62
CreamInstaller/Paradox/ParadoxLauncher.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CreamInstaller.Steam;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace CreamInstaller.Paradox;
|
||||
|
||||
internal static class ParadoxLauncher
|
||||
{
|
||||
private static string installPath = null;
|
||||
internal static string InstallPath
|
||||
{
|
||||
get
|
||||
{
|
||||
installPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation", null) as string;
|
||||
installPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Wow6432Node\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation", null) as string;
|
||||
return installPath;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PopulateDlc(ProgramSelection paradoxLauncher = null)
|
||||
{
|
||||
paradoxLauncher ??= ProgramSelection.FromId("ParadoxLauncher");
|
||||
if (paradoxLauncher is not null)
|
||||
{
|
||||
paradoxLauncher.ExtraDlc.Clear();
|
||||
foreach (ProgramSelection selection in ProgramSelection.AllUsableEnabled)
|
||||
{
|
||||
if (selection == paradoxLauncher) continue;
|
||||
if (selection.AppInfo is null || selection.AppInfo.Value?.GetChild("extended")?.GetChild("publisher")?.ToString() != "Paradox Interactive") continue;
|
||||
paradoxLauncher.ExtraDlc.Add(new(selection.Id, selection.Name, selection.SelectedDlc));
|
||||
}
|
||||
if (!paradoxLauncher.ExtraDlc.Any())
|
||||
foreach (ProgramSelection selection in ProgramSelection.AllUsable)
|
||||
{
|
||||
if (selection == paradoxLauncher) continue;
|
||||
if (selection.AppInfo is null || selection.AppInfo.Value?.GetChild("extended")?.GetChild("publisher")?.ToString() != "Paradox Interactive") continue;
|
||||
paradoxLauncher.ExtraDlc.Add(new(selection.Id, selection.Name, selection.AllDlc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool DlcDialog(Form form)
|
||||
{
|
||||
ProgramSelection paradoxLauncher = ProgramSelection.FromId("ParadoxLauncher");
|
||||
if (paradoxLauncher is not null && paradoxLauncher.Enabled)
|
||||
{
|
||||
PopulateDlc(paradoxLauncher);
|
||||
if (!paradoxLauncher.ExtraDlc.Any())
|
||||
{
|
||||
return new DialogForm(form).Show(SystemIcons.Warning,
|
||||
$"WARNING: There are no installed games with DLC that can be added to the Paradox Launcher!" +
|
||||
"\n\nInstalling CreamAPI/ScreamAPI for the Paradox Launcher is pointless, since no DLC will be added to the configuration!",
|
||||
"Ignore", "Cancel") != DialogResult.OK;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -7,20 +7,22 @@ using System.Reflection;
|
|||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CreamInstaller.Classes;
|
||||
using CreamInstaller.Steam;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller;
|
||||
|
||||
internal static class Program
|
||||
{
|
||||
internal static readonly string ApplicationName = Application.CompanyName + " v" + Application.ProductVersion + ": " + Application.ProductName;
|
||||
internal static readonly string ApplicationNameShort = Application.CompanyName + " v" + Application.ProductVersion;
|
||||
|
||||
internal static readonly Assembly EntryAssembly = Assembly.GetEntryAssembly();
|
||||
internal static readonly Process CurrentProcess = Process.GetCurrentProcess();
|
||||
internal static readonly string CurrentProcessFilePath = CurrentProcess.MainModule.FileName;
|
||||
|
||||
internal static bool BlockProtectedGames = true;
|
||||
internal static readonly string[] ProtectedGameNames = { "PAYDAY 2", "Call to Arms" }; // non-functioning CreamAPI or DLL detections
|
||||
internal static readonly string[] ProtectedGameNames = { "PAYDAY 2", "Call to Arms" }; // non-functioning CreamAPI/ScreamAPI or DLL detections
|
||||
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?
|
||||
|
||||
|
@ -44,9 +46,9 @@ internal static class Program
|
|||
|
||||
internal static bool IsProgramRunningDialog(Form form, ProgramSelection selection)
|
||||
{
|
||||
if (selection.AreSteamApiDllsLocked)
|
||||
if (selection.AreDllsLocked)
|
||||
{
|
||||
if (new DialogForm(form).Show(ApplicationName, SystemIcons.Error,
|
||||
if (new DialogForm(form).Show(SystemIcons.Error,
|
||||
$"ERROR: {selection.Name} is currently running!" +
|
||||
"\n\nPlease close the program/game to continue . . . ",
|
||||
"Retry", "Cancel") == DialogResult.OK)
|
||||
|
@ -56,7 +58,7 @@ internal static class Program
|
|||
return false;
|
||||
}
|
||||
|
||||
internal static void GetApiComponents(this string directory, out string api, out string api_o, out string api64, out string api64_o, out string cApi)
|
||||
internal static void GetCreamApiComponents(this string directory, out string api, out string api_o, out string api64, out string api64_o, out string cApi)
|
||||
{
|
||||
api = directory + @"\steam_api.dll";
|
||||
api_o = directory + @"\steam_api_o.dll";
|
||||
|
@ -65,6 +67,15 @@ internal static class Program
|
|||
cApi = directory + @"\cream_api.ini";
|
||||
}
|
||||
|
||||
internal static void GetScreamApiComponents(this string directory, out string sdk, out string sdk_o, out string sdk64, out string sdk64_o, out string sApi)
|
||||
{
|
||||
sdk = directory + @"\EOSSDK-Win32-Shipping.dll";
|
||||
sdk_o = directory + @"\EOSSDK-Win32-Shipping_o.dll";
|
||||
sdk64 = directory + @"\EOSSDK-Win64-Shipping.dll";
|
||||
sdk64_o = directory + @"\EOSSDK-Win64-Shipping_o.dll";
|
||||
sApi = directory + @"\ScreamAPI.json";
|
||||
}
|
||||
|
||||
[STAThread]
|
||||
private static void Main()
|
||||
{
|
||||
|
|
126
CreamInstaller/ProgramSelection.cs
Normal file
126
CreamInstaller/ProgramSelection.cs
Normal file
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
namespace CreamInstaller;
|
||||
|
||||
internal class ProgramSelection
|
||||
{
|
||||
internal bool Enabled = false;
|
||||
internal bool Usable = true;
|
||||
|
||||
internal string Id = "0";
|
||||
internal string Name = "Program";
|
||||
|
||||
internal string IconStaticID = null;
|
||||
internal string ClientIconStaticID = null;
|
||||
|
||||
internal string RootDirectory = null;
|
||||
internal List<string> DllDirectories = null;
|
||||
|
||||
internal bool IsSteam = false;
|
||||
internal VProperty AppInfo = null;
|
||||
|
||||
internal readonly SortedList<string, (string name, string iconStaticId)> AllDlc = new();
|
||||
internal readonly SortedList<string, (string name, string iconStaticId)> SelectedDlc = new();
|
||||
internal readonly List<Tuple<string, string, SortedList<string, (string name, string iconStaticId)>>> ExtraDlc = new();
|
||||
|
||||
internal bool AreDllsLocked
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (string directory in DllDirectories)
|
||||
{
|
||||
directory.GetCreamApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
if (api.IsFilePathLocked()
|
||||
|| api_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| cApi.IsFilePathLocked())
|
||||
return true;
|
||||
directory.GetScreamApiComponents(out string sdk, out string sdk_o, out string sdk64, out string sdk64_o, out string sApi);
|
||||
if (sdk.IsFilePathLocked()
|
||||
|| sdk_o.IsFilePathLocked()
|
||||
|| sdk64.IsFilePathLocked()
|
||||
|| sdk64_o.IsFilePathLocked()
|
||||
|| sApi.IsFilePathLocked())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Toggle(string dlcAppId, (string name, string iconStaticId) dlcApp, bool enabled)
|
||||
{
|
||||
if (enabled) SelectedDlc[dlcAppId] = dlcApp;
|
||||
else SelectedDlc.Remove(dlcAppId);
|
||||
}
|
||||
|
||||
internal void ToggleDlc(string dlcAppId, bool enabled)
|
||||
{
|
||||
foreach (KeyValuePair<string, (string name, string iconStaticId)> pair in AllDlc)
|
||||
{
|
||||
string appId = pair.Key;
|
||||
(string name, string iconStaticId) dlcApp = pair.Value;
|
||||
if (appId == dlcAppId)
|
||||
{
|
||||
Toggle(appId, dlcApp, enabled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Enabled = SelectedDlc.Any();
|
||||
}
|
||||
|
||||
internal void ToggleAllDlc(bool enabled)
|
||||
{
|
||||
if (!enabled) SelectedDlc.Clear();
|
||||
else foreach (KeyValuePair<string, (string name, string iconStaticId)> pair in AllDlc)
|
||||
{
|
||||
string appId = pair.Key;
|
||||
(string name, string iconStaticId) dlcApp = pair.Value;
|
||||
Toggle(appId, dlcApp, enabled);
|
||||
}
|
||||
Enabled = SelectedDlc.Any();
|
||||
}
|
||||
|
||||
internal ProgramSelection() => All.Add(this);
|
||||
|
||||
internal void Validate()
|
||||
{
|
||||
if (Program.IsGameBlocked(Name, RootDirectory))
|
||||
{
|
||||
All.Remove(this);
|
||||
return;
|
||||
}
|
||||
if (!Directory.Exists(RootDirectory))
|
||||
{
|
||||
All.Remove(this);
|
||||
return;
|
||||
}
|
||||
DllDirectories.RemoveAll(directory => !Directory.Exists(directory));
|
||||
if (!DllDirectories.Any()) All.Remove(this);
|
||||
}
|
||||
|
||||
internal static void ValidateAll() => AllSafe.ForEach(selection => selection.Validate());
|
||||
|
||||
internal static List<ProgramSelection> All = new();
|
||||
|
||||
internal static List<ProgramSelection> AllSafe => All.ToList();
|
||||
|
||||
internal static List<ProgramSelection> AllUsable => All.FindAll(s => s.Usable);
|
||||
|
||||
internal static List<ProgramSelection> AllUsableEnabled => AllUsable.FindAll(s => s.Enabled);
|
||||
|
||||
internal static ProgramSelection FromId(string id) => AllUsable.Find(s => s.Id == id);
|
||||
|
||||
internal static (string gameAppId, (string name, string iconStaticId) app)? GetDlcFromId(string appId)
|
||||
{
|
||||
foreach (ProgramSelection selection in AllUsable)
|
||||
foreach (KeyValuePair<string, (string name, string iconStaticId)> pair in selection.AllDlc)
|
||||
if (pair.Key == appId) return (selection.Id, pair.Value);
|
||||
return null;
|
||||
}
|
||||
}
|
22
CreamInstaller/Properties/Resources.Designer.cs
generated
22
CreamInstaller/Properties/Resources.Designer.cs
generated
|
@ -19,7 +19,7 @@ namespace CreamInstaller.Properties {
|
|||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
@ -89,5 +89,25 @@ namespace CreamInstaller.Properties {
|
|||
return ((System.Drawing.Icon)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] SDK {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("SDK", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] SDK64 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("SDK64", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,12 +112,12 @@
|
|||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="API" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\steam_api.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
|
@ -127,4 +127,10 @@
|
|||
<data name="Icon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\ini.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="SDK" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\EOSSDK-Win32-Shipping.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="SDK64" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\EOSSDK-Win64-Shipping.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
BIN
CreamInstaller/Resources/EOSSDK-Win32-Shipping.dll
Normal file
BIN
CreamInstaller/Resources/EOSSDK-Win32-Shipping.dll
Normal file
Binary file not shown.
BIN
CreamInstaller/Resources/EOSSDK-Win64-Shipping.dll
Normal file
BIN
CreamInstaller/Resources/EOSSDK-Win64-Shipping.dll
Normal file
Binary file not shown.
|
@ -10,7 +10,7 @@ internal static class FileResourceExtensions
|
|||
file.Write(resource);
|
||||
}
|
||||
|
||||
internal static bool Equals(byte[] resource, string filePath)
|
||||
internal static bool EqualsFile(this byte[] resource, string filePath)
|
||||
{
|
||||
byte[] file = File.ReadAllBytes(filePath);
|
||||
if (resource.Length != file.Length)
|
||||
|
|
|
@ -14,7 +14,7 @@ using CreamInstaller.Resources;
|
|||
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
namespace CreamInstaller.Classes;
|
||||
namespace CreamInstaller.Steam;
|
||||
|
||||
internal static class SteamCMD
|
||||
{
|
||||
|
@ -120,6 +120,7 @@ internal static class SteamCMD
|
|||
|
||||
internal static async Task Cleanup() => await Task.Run(async () =>
|
||||
{
|
||||
if (!Directory.Exists(DirectoryPath)) return;
|
||||
await Kill();
|
||||
try
|
||||
{
|
||||
|
@ -171,7 +172,7 @@ internal static class SteamCMD
|
|||
catch { }
|
||||
});
|
||||
|
||||
internal static async Task<VProperty> GetAppInfo(int appId, string branch = "public", int buildId = 0)
|
||||
internal static async Task<VProperty> GetAppInfo(string appId, string branch = "public", int buildId = 0)
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
string output;
|
||||
|
@ -200,10 +201,8 @@ internal static class SteamCMD
|
|||
goto restart;
|
||||
}
|
||||
if (appInfo.Value is VValue)
|
||||
{
|
||||
//new DialogForm(null).Show("GetAppInfo", SystemIcons.Information, "VValue exception:\n\n" + output, "OK");
|
||||
goto restart;
|
||||
}
|
||||
if (appInfo is null || appInfo.Value?.Children()?.ToList()?.Count == 0) return appInfo;
|
||||
VToken type = appInfo.Value?.GetChild("common")?.GetChild("type");
|
||||
if (type is null || type.ToString() == "Game")
|
||||
|
@ -212,8 +211,8 @@ internal static class SteamCMD
|
|||
if (buildid is null && type is not null) return appInfo;
|
||||
if (type is null || int.TryParse(buildid, out int gamebuildId) && gamebuildId < buildId)
|
||||
{
|
||||
List<int> dlcAppIds = await ParseDlcAppIds(appInfo);
|
||||
foreach (int id in dlcAppIds)
|
||||
List<string> dlcAppIds = await ParseDlcAppIds(appInfo);
|
||||
foreach (string id in dlcAppIds)
|
||||
{
|
||||
string dlcAppUpdateFile = $@"{AppInfoPath}\{id}.vdf";
|
||||
if (File.Exists(dlcAppUpdateFile)) File.Delete(dlcAppUpdateFile);
|
||||
|
@ -225,9 +224,9 @@ internal static class SteamCMD
|
|||
return appInfo;
|
||||
}
|
||||
|
||||
internal static async Task<List<int>> ParseDlcAppIds(VProperty appInfo) => await Task.Run(() =>
|
||||
internal static async Task<List<string>> ParseDlcAppIds(VProperty appInfo) => await Task.Run(() =>
|
||||
{
|
||||
List<int> dlcIds = new();
|
||||
List<string> dlcIds = new();
|
||||
#pragma warning disable IDE0150 // Prefer 'null' check over type check
|
||||
if (Program.Canceled || appInfo is not VProperty) return dlcIds;
|
||||
#pragma warning restore IDE0150 // Prefer 'null' check over type check
|
||||
|
@ -236,13 +235,15 @@ internal static class SteamCMD
|
|||
foreach (VProperty property in extended)
|
||||
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);
|
||||
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, out int _)
|
||||
&& int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appid)
|
||||
&& !dlcIds.Contains(appid))
|
||||
dlcIds.Add(appid);
|
||||
&& !dlcIds.Contains("" + appid))
|
||||
dlcIds.Add("" + appid);
|
||||
return dlcIds;
|
||||
});
|
||||
|
||||
|
@ -250,7 +251,6 @@ internal static class SteamCMD
|
|||
{
|
||||
List<Task> tasks = new();
|
||||
foreach (Process process in Process.GetProcessesByName("steamcmd"))
|
||||
{
|
||||
tasks.Add(Task.Run(() =>
|
||||
{
|
||||
try
|
||||
|
@ -260,7 +260,6 @@ internal static class SteamCMD
|
|||
}
|
||||
catch { }
|
||||
}));
|
||||
}
|
||||
foreach (Task task in tasks) await task;
|
||||
}
|
||||
|
|
@ -9,62 +9,64 @@ using Gameloop.Vdf.Linq;
|
|||
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace CreamInstaller.Classes;
|
||||
namespace CreamInstaller.Steam;
|
||||
|
||||
internal static class SteamLibrary
|
||||
{
|
||||
internal static string paradoxLauncherInstallPath = null;
|
||||
internal static string ParadoxLauncherInstallPath
|
||||
private static string installPath = null;
|
||||
internal static string InstallPath
|
||||
{
|
||||
get
|
||||
{
|
||||
paradoxLauncherInstallPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation", null) as string;
|
||||
return paradoxLauncherInstallPath;
|
||||
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam", "InstallPath", null) as string;
|
||||
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Valve\Steam", "InstallPath", null) as string;
|
||||
return installPath;
|
||||
}
|
||||
}
|
||||
|
||||
internal static string steamInstallPath = null;
|
||||
internal static string SteamInstallPath
|
||||
internal static async Task<List<Tuple<string, string, string, int, string>>> GetGames() => await Task.Run(async () =>
|
||||
{
|
||||
get
|
||||
List<Tuple<string, string, string, int, string>> games = new();
|
||||
List<string> gameLibraryDirectories = await GetLibraryDirectories();
|
||||
foreach (string libraryDirectory in gameLibraryDirectories)
|
||||
{
|
||||
steamInstallPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Valve\Steam", "InstallPath", null) as string;
|
||||
steamInstallPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Wow6432Node\Valve\Steam", "InstallPath", null) as string;
|
||||
return steamInstallPath;
|
||||
List<Tuple<string, string, string, int, string>> directoryGames = await GetGamesFromLibraryDirectory(libraryDirectory);
|
||||
if (directoryGames is not null)
|
||||
foreach (Tuple<string, string, string, int, string> game in directoryGames)
|
||||
if (!games.Any(_game => _game.Item1 == game.Item1))
|
||||
games.Add(game);
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task<List<string>> GetLibraryDirectories() => await Task.Run(() =>
|
||||
{
|
||||
List<string> gameDirectories = new();
|
||||
if (Program.Canceled) return gameDirectories;
|
||||
string steamInstallPath = SteamInstallPath;
|
||||
if (steamInstallPath != null && Directory.Exists(steamInstallPath))
|
||||
{
|
||||
string libraryFolder = steamInstallPath + @"\steamapps";
|
||||
if (Directory.Exists(libraryFolder))
|
||||
{
|
||||
gameDirectories.Add(libraryFolder);
|
||||
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
|
||||
if (File.Exists(libraryFolders) && ValveDataFile.TryDeserialize(File.ReadAllText(libraryFolders, Encoding.UTF8), out VProperty result))
|
||||
{
|
||||
foreach (VProperty property in result.Value)
|
||||
if (int.TryParse(property.Key, out int _))
|
||||
{
|
||||
string path = property.Value.GetChild("path")?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(path)) continue;
|
||||
path += @"\steamapps";
|
||||
if (Directory.Exists(path) && !gameDirectories.Contains(path)) gameDirectories.Add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return gameDirectories;
|
||||
return games;
|
||||
});
|
||||
|
||||
internal static async Task<List<Tuple<int, string, string, int, string>>> GetGamesFromLibraryDirectory(string libraryDirectory) => await Task.Run(() =>
|
||||
internal static async Task<List<string>> GetDllDirectoriesFromGameDirectory(string gameDirectory) => await Task.Run(async () =>
|
||||
{
|
||||
List<Tuple<int, string, string, int, string>> games = new();
|
||||
List<string> dllDirectories = new();
|
||||
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
|
||||
gameDirectory.GetCreamApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
if (File.Exists(api)
|
||||
|| File.Exists(api_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| File.Exists(cApi))
|
||||
dllDirectories.Add(gameDirectory);
|
||||
string[] directories = Directory.GetDirectories(gameDirectory);
|
||||
foreach (string _directory in directories)
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
try
|
||||
{
|
||||
List<string> moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
|
||||
if (moreDllDirectories is not null) dllDirectories.AddRange(moreDllDirectories);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return !dllDirectories.Any() ? null : dllDirectories;
|
||||
});
|
||||
|
||||
internal static async Task<List<Tuple<string, string, string, int, string>>> GetGamesFromLibraryDirectory(string libraryDirectory) => await Task.Run(() =>
|
||||
{
|
||||
List<Tuple<string, string, string, int, string>> games = new();
|
||||
if (Program.Canceled || !Directory.Exists(libraryDirectory)) return null;
|
||||
string[] files = Directory.GetFiles(libraryDirectory);
|
||||
foreach (string file in files)
|
||||
|
@ -86,34 +88,35 @@ internal static class SteamLibrary
|
|||
string gameDirectory = libraryDirectory + @"\common\" + installdir;
|
||||
if (!int.TryParse(appId, out int appIdInt)) continue;
|
||||
if (!int.TryParse(buildId, out int buildIdInt)) continue;
|
||||
games.Add(new(appIdInt, name, branch, buildIdInt, gameDirectory));
|
||||
games.Add(new(appId, name, branch, buildIdInt, gameDirectory));
|
||||
}
|
||||
}
|
||||
return !games.Any() ? null : games;
|
||||
});
|
||||
|
||||
internal static async Task<List<string>> GetDllDirectoriesFromGameDirectory(string gameDirectory) => await Task.Run(async () =>
|
||||
internal static async Task<List<string>> GetLibraryDirectories() => await Task.Run(() =>
|
||||
{
|
||||
List<string> dllDirectories = new();
|
||||
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
|
||||
gameDirectory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
|
||||
if (File.Exists(api)
|
||||
|| File.Exists(api_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| File.Exists(cApi))
|
||||
dllDirectories.Add(gameDirectory);
|
||||
string[] directories = Directory.GetDirectories(gameDirectory);
|
||||
foreach (string _directory in directories)
|
||||
List<string> gameDirectories = new();
|
||||
if (Program.Canceled) return gameDirectories;
|
||||
string steamInstallPath = InstallPath;
|
||||
if (steamInstallPath != null && Directory.Exists(steamInstallPath))
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
try
|
||||
string libraryFolder = steamInstallPath + @"\steamapps";
|
||||
if (Directory.Exists(libraryFolder))
|
||||
{
|
||||
List<string> moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
|
||||
if (moreDllDirectories is not null) dllDirectories.AddRange(moreDllDirectories);
|
||||
gameDirectories.Add(libraryFolder);
|
||||
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
|
||||
if (File.Exists(libraryFolders) && ValveDataFile.TryDeserialize(File.ReadAllText(libraryFolders, Encoding.UTF8), out VProperty result))
|
||||
foreach (VProperty property in result.Value)
|
||||
if (int.TryParse(property.Key, out int _))
|
||||
{
|
||||
string path = property.Value.GetChild("path")?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(path)) continue;
|
||||
path += @"\steamapps";
|
||||
if (Directory.Exists(path) && !gameDirectories.Contains(path)) gameDirectories.Add(path);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return !dllDirectories.Any() ? null : dllDirectories;
|
||||
return gameDirectories;
|
||||
});
|
||||
}
|
24
CreamInstaller/Steam/SteamStore.cs
Normal file
24
CreamInstaller/Steam/SteamStore.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using HtmlAgilityPack;
|
||||
|
||||
namespace CreamInstaller.Steam;
|
||||
|
||||
internal static class SteamStore
|
||||
{
|
||||
internal static async Task ParseDlcAppIds(string appId, List<string> dlcIds)
|
||||
{
|
||||
// currently this is only really needed to get DLC that release without changing game buildid (very rare)
|
||||
// it also finds things which aren't really connected to the game itself, and thus not needed (usually soundtracks, collections, packs, etc.)
|
||||
HtmlNodeCollection nodes = await HttpClientManager.GetDocumentNodes(
|
||||
$"https://store.steampowered.com/dlc/{appId}",
|
||||
"//div[@class='recommendation']/div/a");
|
||||
if (nodes is not null)
|
||||
foreach (HtmlNode node in nodes)
|
||||
if (int.TryParse(node.Attributes?["data-ds-appid"]?.Value, out int dlcAppId) && dlcAppId > 0 && !dlcIds.Contains("" + dlcAppId))
|
||||
dlcIds.Add("" + dlcAppId);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
using Gameloop.Vdf;
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
namespace CreamInstaller.Classes;
|
||||
namespace CreamInstaller.Steam;
|
||||
|
||||
internal static class ValveDataFile
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace CreamInstaller.Classes;
|
||||
namespace CreamInstaller.Utility;
|
||||
|
||||
internal static class Diagnostics
|
||||
{
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CreamInstaller.Classes;
|
||||
namespace CreamInstaller.Utility;
|
||||
|
||||
internal static class ExceptionHandler
|
||||
{
|
50
CreamInstaller/Utility/HttpClientManager.cs
Normal file
50
CreamInstaller/Utility/HttpClientManager.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using HtmlAgilityPack;
|
||||
|
||||
namespace CreamInstaller.Utility;
|
||||
|
||||
internal static class HttpClientManager
|
||||
{
|
||||
internal static HttpClient HttpClient;
|
||||
internal static void Setup()
|
||||
{
|
||||
HttpClient = new();
|
||||
HttpClient.DefaultRequestHeaders.Add("user-agent", $"CreamInstaller-{Environment.MachineName}_{Environment.UserDomainName}_{Environment.UserName}");
|
||||
}
|
||||
|
||||
internal static async Task<HtmlDocument> Get(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
using HttpRequestMessage request = new(HttpMethod.Get, url);
|
||||
using HttpResponseMessage response = await HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||
response.EnsureSuccessStatusCode();
|
||||
using Stream stream = await response.Content.ReadAsStreamAsync();
|
||||
using StreamReader reader = new(stream, Encoding.UTF8);
|
||||
HtmlDocument document = new();
|
||||
document.LoadHtml(reader.ReadToEnd());
|
||||
return document;
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
internal static async Task<HtmlNodeCollection> GetDocumentNodes(string url, string xpath) => (await Get(url))?.DocumentNode?.SelectNodes(xpath);
|
||||
|
||||
internal static async Task<Image> GetImageFromUrl(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new Bitmap(await HttpClient.GetStreamAsync(url));
|
||||
}
|
||||
catch { }
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static void Dispose() => HttpClient.Dispose();
|
||||
}
|
|
@ -3,7 +3,7 @@ using System.Drawing;
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CreamInstaller.Classes;
|
||||
namespace CreamInstaller.Utility;
|
||||
|
||||
internal static class IconGrabber
|
||||
{
|
||||
|
@ -14,8 +14,8 @@ internal static class IconGrabber
|
|||
}
|
||||
|
||||
private static readonly string SteamAppImagesPath = "https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/";
|
||||
internal static async Task<Image> GetSteamIcon(int steamAppId, string iconStaticId) => await HttpClientManager.GetImageFromUrl(SteamAppImagesPath + $"/{steamAppId}/{iconStaticId}.jpg");
|
||||
internal static async Task<Image> GetSteamClientIcon(int steamAppId, string clientIconStaticId) => await HttpClientManager.GetImageFromUrl(SteamAppImagesPath + $"/{steamAppId}/{clientIconStaticId}.ico");
|
||||
internal static async Task<Image> GetSteamIcon(string steamAppId, string iconStaticId) => await HttpClientManager.GetImageFromUrl(SteamAppImagesPath + $"/{steamAppId}/{iconStaticId}.jpg");
|
||||
internal static async Task<Image> GetSteamClientIcon(string steamAppId, string clientIconStaticId) => await HttpClientManager.GetImageFromUrl(SteamAppImagesPath + $"/{steamAppId}/{clientIconStaticId}.ico");
|
||||
|
||||
internal static Image GetFileIconImage(string path) => File.Exists(path) ? Icon.ExtractAssociatedIcon(path).ToBitmap() : null;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CreamInstaller.Classes;
|
||||
namespace CreamInstaller.Utility;
|
||||
|
||||
internal static class InstallationLog
|
||||
{
|
Loading…
Reference in a new issue