heroic games launcher support

This commit is contained in:
pointfeev 2023-05-27 22:02:22 -04:00
parent d08c7c50a7
commit 0974f78889
5 changed files with 94 additions and 29 deletions

View file

@ -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;

View file

@ -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<HashSet<Manifest>> GetGames()
=> await Task.Run(() =>
=> await Task.Run(async () =>
{
HashSet<Manifest> 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<Manifest>(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<Manifest>(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;
});
}

View file

@ -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; }
}

View file

@ -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<Manifest> 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<HeroicAppData>();
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
}
});
}

View file

@ -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; }
}