Skip to content

Commit

Permalink
Merge pull request #2103 from erri120/heroic
Browse files Browse the repository at this point in the history
Find GOG games installed with the Heroic launcher
  • Loading branch information
erri120 authored Sep 30, 2024
2 parents 3f23812 + 0b12554 commit 7e795ca
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 4 deletions.
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<PackageVersion Include="AvaloniaEdit.TextMate" Version="11.1.0" />
<PackageVersion Include="FlatSharp.Compiler" Version="7.6.0" />
<PackageVersion Include="FlatSharp.Runtime" Version="7.6.0" />
<PackageVersion Include="GameFinder.Launcher.Heroic" Version="4.3.0" />
<PackageVersion Include="LinqGen" Version="0.3.1" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="8.8.0" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.0" />
Expand Down Expand Up @@ -120,7 +121,7 @@
<PackageVersion Include="BitFaster.Caching" Version="2.5.0" />
<PackageVersion Include="CliWrap" Version="3.6.6" />
<PackageVersion Include="DynamicData" Version="9.0.4" />
<PackageVersion Include="GameFinder" Version="4.2.4" />
<PackageVersion Include="GameFinder" Version="4.3.0" />
<PackageVersion Include="Humanizer" Version="2.14.1" />
<PackageVersion Include="ini-parser-netstandard" Version="2.5.2" />
<PackageVersion Include="Mutagen.Bethesda.Skyrim" Version="0.44.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ public record GOGLocatorResultMetadata : IGameLocatorResultMetadata
/// </summary>
public required long Id { get; init; }
}

[PublicAPI]
public record HeroicGOGLocatorResultMetadata : GOGLocatorResultMetadata;
23 changes: 20 additions & 3 deletions src/Abstractions/NexusMods.Abstractions.Games/RunGameTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Extensions.Logging;
using NexusMods.Abstractions.GameLocators;
using NexusMods.Abstractions.Games.DTO;
using NexusMods.Abstractions.Games.Stores.GOG;
using NexusMods.Abstractions.Games.Stores.Steam;
using NexusMods.Abstractions.Loadouts;
using NexusMods.CrossPlatform.Process;
Expand Down Expand Up @@ -60,10 +61,18 @@ public async Task Execute(Loadout.ReadOnly loadout, CancellationToken cancellati
var program = await GetGamePath(loadout);
var primaryFile = _game.GetPrimaryFile(loadout.InstallationInstance.Store).CombineChecked(loadout.InstallationInstance);

if (OSInformation.Shared.IsLinux && program.Equals(primaryFile) && loadout.InstallationInstance.LocatorResultMetadata is SteamLocatorResultMetadata steamLocatorResultMetadata)
if (OSInformation.Shared.IsLinux && program.Equals(primaryFile))
{
await RunThroughSteam(steamLocatorResultMetadata.AppId, cancellationToken);
return;
var locator = loadout.InstallationInstance.LocatorResultMetadata;
switch (locator)
{
case SteamLocatorResultMetadata steamLocatorResultMetadata:
await RunThroughSteam(steamLocatorResultMetadata.AppId, cancellationToken);
return;
case HeroicGOGLocatorResultMetadata heroicGOGLocatorResultMetadata:
await RunThroughHeroic("gog", heroicGOGLocatorResultMetadata.Id, cancellationToken);
return;
}
}

var names = new HashSet<string>
Expand Down Expand Up @@ -177,6 +186,14 @@ private async Task RunThroughSteam(uint appId, CancellationToken cancellationTok
await reaper.WaitForExitAsync(cancellationToken);
}

private async Task RunThroughHeroic(string type, long appId, CancellationToken cancellationToken)
{
Debug.Assert(OSInformation.Shared.IsLinux);

// TODO: track process
await _osInterop.OpenUrl(new Uri($"heroic://launch/{type}/{appId.ToString(CultureInfo.InvariantCulture)}"), fireAndForget: true, cancellationToken: cancellationToken);
}

private async ValueTask<Process?> WaitForProcessToStart(
string processName,
TimeSpan timeout,
Expand Down
53 changes: 53 additions & 0 deletions src/NexusMods.StandardGameLocators/HeroicGogLocator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using GameFinder.Launcher.Heroic;
using GameFinder.StoreHandlers.GOG;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NexusMods.Abstractions.GameLocators;
using NexusMods.Abstractions.GameLocators.Stores.GOG;
using NexusMods.Abstractions.Games.Stores.GOG;

namespace NexusMods.StandardGameLocators;

/// <summary>
/// Find GOG games installed with the Heroic launcher.
/// </summary>
public class HeroicGogLocator : IGameLocator
{
private readonly ILogger _logger;

private readonly HeroicGOGHandler _handler;
private IReadOnlyDictionary<GOGGameId, GOGGame>? _cachedGames;

/// <summary>
/// Constructor.
/// </summary>
public HeroicGogLocator(IServiceProvider provider)
{
_logger = provider.GetRequiredService<ILogger<HeroicGogLocator>>();
_handler = provider.GetRequiredService<HeroicGOGHandler>();
}

public IEnumerable<GameLocatorResult> Find(ILocatableGame game)
{
if (game is not IGogGame tg) yield break;

if (_cachedGames is null)
{
_cachedGames = _handler.FindAllGamesById(out var errors);
if (errors.Any())
{
foreach (var error in errors)
_logger.LogError("While looking for games: {Error}", error);
}
}

foreach (var id in tg.GogIds)
{
if (!_cachedGames.TryGetValue(GOGGameId.From(id), out var found)) continue;
yield return new GameLocatorResult(found.Path, GameStore.GOG, new HeroicGOGLocatorResultMetadata
{
Id = id,
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<ItemGroup>
<PackageReference Include="GameFinder" />
<PackageReference Include="GameFinder.Launcher.Heroic" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
</ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions src/NexusMods.StandardGameLocators/Services.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text.Json.Serialization;
using GameFinder.Common;
using GameFinder.Launcher.Heroic;
using GameFinder.RegistryUtils;
using GameFinder.StoreHandlers.EADesktop;
using GameFinder.StoreHandlers.EADesktop.Crypto;
Expand Down Expand Up @@ -61,6 +62,7 @@ public static IServiceCollection AddStandardGameLocators(
onLinux: () =>
{
services.AddSingleton<IGameLocator, SteamLocator>();
services.AddSingleton<IGameLocator, HeroicGogLocator>();

services.AddSingleton<IGameLocator, DefaultWineGameLocator>();
services.AddSingleton<IGameLocator, BottlesWineGameLocator>();
Expand Down Expand Up @@ -92,6 +94,7 @@ public static IServiceCollection AddStandardGameLocators(
onLinux: () =>
{
services.AddSingleton<AHandler<SteamGame, AppId>>(provider => new SteamHandler(provider.GetRequiredService<IFileSystem>(), registry: null));
services.AddSingleton<HeroicGOGHandler>(provider => new HeroicGOGHandler(provider.GetRequiredService<IFileSystem>()));

services.AddSingleton<IWinePrefixManager<WinePrefix>>(provider => new DefaultWinePrefixManager(provider.GetRequiredService<IFileSystem>()));
services.AddSingleton<IWinePrefixManager<BottlesWinePrefix>>(provider => new BottlesWinePrefixManager(provider.GetRequiredService<IFileSystem>()));
Expand Down
3 changes: 3 additions & 0 deletions tests/NexusMods.StandardGameLocators.TestHelpers/Services.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GameFinder.Common;
using GameFinder.Launcher.Heroic;
using GameFinder.StoreHandlers.EADesktop;
using GameFinder.StoreHandlers.EGS;
using GameFinder.StoreHandlers.GOG;
Expand Down Expand Up @@ -75,6 +76,8 @@ public static IServiceCollection AddStubbedGameLocators(this IServiceCollection

if (OSInformation.Shared.IsLinux)
{
coll.AddSingleton<HeroicGOGHandler>(s => new HeroicGOGHandler(s.GetRequiredService<IFileSystem>()));

coll.AddSingleton<IWinePrefixManager<WinePrefix>>(s =>
new StubbedWinePrefixManager<WinePrefix>(s.GetRequiredService<TemporaryFileManager>(),
tfm => new WinePrefix
Expand Down

0 comments on commit 7e795ca

Please sign in to comment.