Skip to content

Commit 2fce4fb

Browse files
committed
Provide wine prefix for heroic
1 parent 504d7c7 commit 2fce4fb

File tree

7 files changed

+103
-10
lines changed

7 files changed

+103
-10
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com) and this p
88

99
## [Released](https://github.com/erri120/GameFinder/releases)
1010

11+
## [4.3.1](https://github.com/erri120/GameFinder/compare/v4.3.0...v4.3.1) - 2024-10-01
12+
13+
- Heroic: pass along the wine prefix
14+
1115
## [4.3.0](https://github.com/erri120/GameFinder/compare/v4.2.4...v4.3.0) - 2024-09-28
1216

1317
Adds support for Heroic.

src/GameFinder.Launcher.Heroic/DTOs/Json.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,34 @@ internal record Root(
2222
[property: JsonPropertyName("installed")] IReadOnlyList<Installed> Installed
2323
);
2424

25+
internal record GameConfig(
26+
[property: JsonPropertyName("autoInstallDxvk")] bool AutoInstallDxvk,
27+
[property: JsonPropertyName("autoInstallDxvkNvapi")] bool AutoInstallDxvkNvapi,
28+
[property: JsonPropertyName("autoInstallVkd3d")] bool AutoInstallVkd3d,
29+
[property: JsonPropertyName("preferSystemLibs")] bool PreferSystemLibs,
30+
[property: JsonPropertyName("enableEsync")] bool EnableEsync,
31+
[property: JsonPropertyName("enableMsync")] bool EnableMsync,
32+
[property: JsonPropertyName("enableFsync")] bool EnableFsync,
33+
[property: JsonPropertyName("nvidiaPrime")] bool NvidiaPrime,
34+
[property: JsonPropertyName("enviromentOptions")] IReadOnlyList<object> EnviromentOptions,
35+
[property: JsonPropertyName("wrapperOptions")] IReadOnlyList<object> WrapperOptions,
36+
[property: JsonPropertyName("showFps")] bool ShowFps,
37+
[property: JsonPropertyName("useGameMode")] bool UseGameMode,
38+
[property: JsonPropertyName("battlEyeRuntime")] bool BattlEyeRuntime,
39+
[property: JsonPropertyName("eacRuntime")] bool EacRuntime,
40+
[property: JsonPropertyName("language")] string Language,
41+
[property: JsonPropertyName("beforeLaunchScriptPath")] string BeforeLaunchScriptPath,
42+
[property: JsonPropertyName("afterLaunchScriptPath")] string AfterLaunchScriptPath,
43+
[property: JsonPropertyName("wineVersion")] WineVersion WineVersion,
44+
[property: JsonPropertyName("winePrefix")] string WinePrefix,
45+
[property: JsonPropertyName("wineCrossoverBottle")] string WineCrossoverBottle
46+
);
47+
48+
public record WineVersion(
49+
[property: JsonPropertyName("bin")] string Bin,
50+
[property: JsonPropertyName("name")] string Name,
51+
[property: JsonPropertyName("type")] string Type
52+
);
53+
2554

2655

src/GameFinder.Launcher.Heroic/GameFinder.Launcher.Heroic.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55

66
<ItemGroup>
77
<ProjectReference Include="..\GameFinder.StoreHandlers.GOG\GameFinder.StoreHandlers.GOG.csproj" />
8+
<ProjectReference Include="..\GameFinder.Wine\GameFinder.Wine.csproj" />
89
</ItemGroup>
910
</Project>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using GameFinder.StoreHandlers.GOG;
2+
using GameFinder.Wine;
3+
using NexusMods.Paths;
4+
5+
namespace GameFinder.Launcher.Heroic;
6+
7+
public record HeroicGOGGame(
8+
GOGGameId Id,
9+
string Name,
10+
AbsolutePath Path,
11+
AbsolutePath WinePrefixPath,
12+
DTOs.WineVersion WineVersion) : GOGGame(Id, Name, Path)
13+
{
14+
public WinePrefix GetWinePrefix()
15+
{
16+
return new WinePrefix
17+
{
18+
ConfigurationDirectory = WinePrefixPath.Combine("pfx"),
19+
UserName = "steamuser",
20+
};
21+
}
22+
}

src/GameFinder.Launcher.Heroic/HeroicGOGHandler.cs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics.CodeAnalysis;
34
using System.Globalization;
45
using System.IO;
56
using System.Linq;
@@ -20,6 +21,7 @@ public class HeroicGOGHandler : AHandler<GOGGame, GOGGameId>
2021
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
2122
{
2223
AllowTrailingCommas = true,
24+
ReadCommentHandling = JsonCommentHandling.Skip,
2325
};
2426

2527
/// <summary>
@@ -39,24 +41,25 @@ public HeroicGOGHandler(IFileSystem fileSystem)
3941
/// <inheritdoc/>
4042
public override IEnumerable<OneOf<GOGGame, ErrorMessage>> FindAllGames()
4143
{
42-
var installedJsonFile = FindConfigDirectory(_fileSystem)
43-
.Select(GetInstalledJsonFilePath)
44-
.FirstOrDefault(path => path.FileExists);
44+
var configDirectory = FindConfigDirectory(_fileSystem)
45+
.FirstOrDefault(path => path.DirectoryExists());
4546

46-
if (installedJsonFile == default)
47+
if (configDirectory == default)
4748
{
4849
yield return new ErrorMessage("Didn't find any heroic files, this can be ignored if heroic isn't installed");
4950
yield break;
5051
}
5152

52-
var games = ParseInstalledJsonFile(installedJsonFile);
53+
var installedJsonFile = GetInstalledJsonFilePath(configDirectory);
54+
55+
var games = ParseInstalledJsonFile(installedJsonFile, configDirectory);
5356
foreach (var x in games)
5457
{
5558
yield return x;
5659
}
5760
}
5861

59-
internal static IEnumerable<OneOf<GOGGame, ErrorMessage>> ParseInstalledJsonFile(AbsolutePath path)
62+
internal static IEnumerable<OneOf<GOGGame, ErrorMessage>> ParseInstalledJsonFile(AbsolutePath path, AbsolutePath configPath)
6063
{
6164
using var stream = path.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
6265
var root = JsonSerializer.Deserialize<DTOs.Root>(stream, JsonSerializerOptions);
@@ -71,7 +74,7 @@ internal static IEnumerable<OneOf<GOGGame, ErrorMessage>> ParseInstalledJsonFile
7174
OneOf<GOGGame, ErrorMessage> res;
7275
try
7376
{
74-
res = Parse(installed, path.FileSystem);
77+
res = Parse(installed, configPath, path.FileSystem);
7578
}
7679
catch (Exception e)
7780
{
@@ -82,15 +85,40 @@ internal static IEnumerable<OneOf<GOGGame, ErrorMessage>> ParseInstalledJsonFile
8285
}
8386
}
8487

85-
internal static OneOf<GOGGame, ErrorMessage> Parse(DTOs.Installed installed, IFileSystem fileSystem)
88+
[RequiresUnreferencedCode("Calls System.Text.Json.JsonSerializer.Deserialize<TValue>(JsonSerializerOptions)")]
89+
internal static OneOf<GOGGame, ErrorMessage> Parse(
90+
DTOs.Installed installed,
91+
AbsolutePath configPath,
92+
IFileSystem fileSystem)
8693
{
8794
if (!long.TryParse(installed.AppName, NumberStyles.Integer, CultureInfo.InvariantCulture, out var id))
8895
{
8996
return new ErrorMessage($"The value \"appName\" is not a number: \"{installed.AppName}\"");
9097
}
9198

99+
var gamesConfigFile = GetGamesConfigJsonFile(configPath, id.ToString(CultureInfo.InvariantCulture));
100+
if (!gamesConfigFile.FileExists) return new ErrorMessage($"File `{gamesConfigFile}` doesn't exist!");
101+
102+
using var stream = gamesConfigFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
103+
using var doc = JsonDocument.Parse(stream, new JsonDocumentOptions
104+
{
105+
AllowTrailingCommas = true,
106+
CommentHandling = JsonCommentHandling.Skip,
107+
});
108+
109+
var element = doc.RootElement.GetProperty(id.ToString(CultureInfo.InvariantCulture));
110+
var gameConfig = element.Deserialize<DTOs.GameConfig>();
111+
if (gameConfig is null) return new ErrorMessage($"Unable to deserialize `{gamesConfigFile}`");
112+
92113
var path = fileSystem.FromUnsanitizedFullPath(installed.InstallPath);
93-
return new GOGGame(GOGGameId.From(id), installed.AppName, path);
114+
var winePrefixPath = fileSystem.FromUnsanitizedFullPath(gameConfig.WinePrefix);
115+
116+
return new HeroicGOGGame(GOGGameId.From(id), installed.AppName, path, winePrefixPath, gameConfig.WineVersion);
117+
}
118+
119+
internal static AbsolutePath GetGamesConfigJsonFile(AbsolutePath configPath, string name)
120+
{
121+
return configPath.Combine("GamesConfig").Combine($"{name}.json");
94122
}
95123

96124
internal static AbsolutePath GetInstalledJsonFilePath(AbsolutePath configPath)

src/GameFinder.Wine/WinePrefix.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,12 @@ namespace GameFinder.Wine;
66
/// Represents a wine prefix.
77
/// </summary>
88
[PublicAPI]
9-
public record WinePrefix : AWinePrefix;
9+
public record WinePrefix : AWinePrefix
10+
{
11+
public string? UserName { get; init; }
12+
13+
protected override string GetUserName()
14+
{
15+
return UserName ?? base.GetUserName();
16+
}
17+
}

src/GameFinder/GameFinder.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<ProjectReference Include="..\GameFinder.StoreHandlers.Steam\GameFinder.StoreHandlers.Steam.csproj" />
2222
<ProjectReference Include="..\GameFinder.StoreHandlers.Xbox\GameFinder.StoreHandlers.Xbox.csproj" />
2323
<ProjectReference Include="..\GameFinder.Wine\GameFinder.Wine.csproj" />
24+
<ProjectReference Include="..\GameFinder.Launcher.Heroic\GameFinder.Launcher.Heroic.csproj" />
2425
</ItemGroup>
2526

2627
</Project>

0 commit comments

Comments
 (0)