diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/SelectForm.cs index 56fa244..bc60842 100644 --- a/CreamInstaller/Forms/SelectForm.cs +++ b/CreamInstaller/Forms/SelectForm.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using System.Windows.Forms; using CreamInstaller.Components; using CreamInstaller.Platforms.Epic; +using CreamInstaller.Platforms.Epic.Heroic; using CreamInstaller.Platforms.Paradox; using CreamInstaller.Platforms.Steam; using CreamInstaller.Platforms.Ubisoft; @@ -647,7 +648,7 @@ internal sealed partial class SelectForm : CustomForm => !Program.IsGameBlocked(g.name, g.gameDirectory))) gameChoices.Add((Platform.Steam, appId, name, programsToScan is not null && programsToScan.Any(p => p.platform is Platform.Steam && p.id == appId))); - if (EpicLibrary.EpicManifestsPath.DirectoryExists()) + if (EpicLibrary.EpicManifestsPath.DirectoryExists() || HeroicLibrary.HeroicLibraryPath.DirectoryExists()) gameChoices.AddRange((await EpicLibrary.GetGames()).Where(m => !Program.IsGameBlocked(m.DisplayName, m.InstallLocation)).Select(manifest => (Platform.Epic, manifest.CatalogNamespace, manifest.DisplayName, programsToScan is not null && programsToScan.Any(p => p.platform is Platform.Epic && p.id == manifest.CatalogNamespace)))); @@ -659,7 +660,7 @@ internal sealed partial class SelectForm : CustomForm using SelectDialogForm form = new(this); DialogResult selectResult = form.QueryUser("Choose which programs and/or games to scan:", gameChoices, out List<(Platform platform, string id, string name)> choices); - if (selectResult == DialogResult.Abort) // will be an uninstall all button + if (selectResult == DialogResult.Abort) { int maxProgress = 0; int curProgress = 0; diff --git a/CreamInstaller/Platforms/Epic/EpicLibrary.cs b/CreamInstaller/Platforms/Epic/EpicLibrary.cs index 52d7f2d..2ae784f 100644 --- a/CreamInstaller/Platforms/Epic/EpicLibrary.cs +++ b/CreamInstaller/Platforms/Epic/EpicLibrary.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using CreamInstaller.Platforms.Epic.Heroic; using CreamInstaller.Utility; using Microsoft.Win32; using Newtonsoft.Json; @@ -29,29 +30,31 @@ internal static class EpicLibrary => await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true)); internal static async Task> GetGames() - => await Task.Run(() => + => await Task.Run(async () => { HashSet games = new(); string manifests = EpicManifestsPath; - if (!manifests.DirectoryExists()) + if (manifests.DirectoryExists()) + foreach (string item in manifests.EnumerateDirectory("*.item")) + { + if (Program.Canceled) + return games; + string json = item.ReadFile(); + try + { + Manifest manifest = JsonConvert.DeserializeObject(json); + if (manifest is not null && !games.Any(g + => g.CatalogNamespace == manifest.CatalogNamespace && g.InstallLocation == manifest.InstallLocation)) + _ = games.Add(manifest); + } + catch + { + // ignored + } + } + if (Program.Canceled) return games; - foreach (string file in manifests.EnumerateDirectory("*.item")) - { - if (Program.Canceled) - return games; - string json = file.ReadFile(); - try - { - Manifest manifest = JsonConvert.DeserializeObject(json); - if (manifest is not null && manifest.CatalogItemId == manifest.MainGameCatalogItemId && !games.Any(g - => g.CatalogItemId == manifest.CatalogItemId && g.InstallLocation == manifest.InstallLocation)) - _ = games.Add(manifest); - } - catch - { - // ignored - } - } + await HeroicLibrary.GetGames(games); return games; }); } \ No newline at end of file diff --git a/CreamInstaller/Platforms/Epic/Heroic/HeroicAppData.cs b/CreamInstaller/Platforms/Epic/Heroic/HeroicAppData.cs new file mode 100644 index 0000000..4f28d1e --- /dev/null +++ b/CreamInstaller/Platforms/Epic/Heroic/HeroicAppData.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace CreamInstaller.Platforms.Epic.Heroic; + +public class HeroicInstall +{ + [JsonProperty("install_path")] public string InstallPath { get; set; } +} + +public class HeroicAppData +{ + [JsonProperty("install")] public HeroicInstall Install { get; set; } + + [JsonProperty("namespace")] public string Namespace { get; set; } + + [JsonProperty("title")] public string Title { get; set; } + + [JsonProperty("runner")] public string Runner { get; set; } +} \ No newline at end of file diff --git a/CreamInstaller/Platforms/Epic/Heroic/HeroicLibrary.cs b/CreamInstaller/Platforms/Epic/Heroic/HeroicLibrary.cs new file mode 100644 index 0000000..5960228 --- /dev/null +++ b/CreamInstaller/Platforms/Epic/Heroic/HeroicLibrary.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using CreamInstaller.Utility; +using Newtonsoft.Json.Linq; + +namespace CreamInstaller.Platforms.Epic.Heroic; + +internal static class HeroicLibrary +{ + internal static readonly string HeroicLibraryPath + = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\heroic\store_cache\legendary_library.json"; + + internal static async Task GetGames(HashSet games) + => await Task.Run(() => + { + string libraryPath = HeroicLibraryPath; + if (!libraryPath.FileExists()) + return; + string libraryJson = libraryPath.ReadFile(); + try + { + JObject library = JObject.Parse(libraryJson); + if (!library.TryGetValue("library", out JToken libraryToken) || libraryToken is not JArray libraryArray) + return; + foreach (JToken token in libraryArray) + try + { + HeroicAppData appData = token.ToObject(); + if (appData is null || appData.Runner != "legendary" || string.IsNullOrWhiteSpace(appData.Install.InstallPath)) + continue; + Manifest manifest = new() + { + DisplayName = appData.Title, CatalogNamespace = appData.Namespace, InstallLocation = appData.Install.InstallPath + }; + if (!games.Any(g => g.CatalogNamespace == manifest.CatalogNamespace && g.InstallLocation == manifest.InstallLocation)) + _ = games.Add(manifest); + } + catch + { + // ignored + } + } + catch + { + // ignored + } + }); +} \ No newline at end of file diff --git a/CreamInstaller/Platforms/Epic/Manifest.cs b/CreamInstaller/Platforms/Epic/Manifest.cs index a79667b..2945284 100644 --- a/CreamInstaller/Platforms/Epic/Manifest.cs +++ b/CreamInstaller/Platforms/Epic/Manifest.cs @@ -6,13 +6,5 @@ public class Manifest public string InstallLocation { get; set; } - public string LaunchExecutable { get; set; } - public string CatalogNamespace { get; set; } - - public string CatalogItemId { get; set; } - - public string MainGameCatalogNamespace { get; set; } - - public string MainGameCatalogItemId { get; set; } } \ No newline at end of file