Skip to content

Commit ed28bcb

Browse files
authored
Merge pull request #17 from tekgator/dev
v1.3.2
2 parents 16ce16c + 8f03c2f commit ed28bcb

File tree

23 files changed

+264
-67
lines changed

23 files changed

+264
-67
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
44
## [Unreleased]
55

66

7+
## [1.3.2] - 2022-16-09
8+
### Added
9+
- Add LauncherOption to also search for additional executables within a game install directory
10+
- Add Executables property to IGame interface to list all additional executables within a game install directory
11+
12+
### Fixed
13+
- Steam plugin was not processing manifest entries in parallel
14+
15+
716
## [1.3.1] - 2022-11-09
817
### Fixed
918
- Activate parallel processing of installed games for Battle.net and Rockstar Games

GameLib.Core/IGame.cs

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ public interface IGame
3434
/// </summary>
3535
public Icon? ExecutableIcon { get; }
3636

37+
/// <summary>
38+
/// Additional executables found within the install directory
39+
/// </summary>
40+
public IEnumerable<string> Executables { get; }
41+
3742
/// <summary>
3843
/// Working directory of the game
3944
/// </summary>

GameLib.Core/LauncherOptions.cs

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
public class LauncherOptions
44
{
55
/// <summary>
6-
/// Define if Launcher plugin should use local catalog data (if present)
6+
/// Define if Launcher plugin should use local catalog data (if present)
77
/// to get more detailed information about specific games
88
/// Note: Can in increase load time for the plugin
99
/// </summary>
@@ -23,5 +23,10 @@ public class LauncherOptions
2323
/// <summary>
2424
/// Defines the timeout time for online query's
2525
/// </summary>
26-
public TimeSpan? OnlineQueryTimeout { get; init; } = null;
26+
public TimeSpan? OnlineQueryTimeout { get; init; }
27+
28+
/// <summary>
29+
/// Search all possible game executables within the install directory and sub directories
30+
/// </summary>
31+
public bool SearchExecutables { get; init; } = true;
2732
}

GameLib.Core/Util/PathUtil.cs

+5
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,9 @@ public static bool IsExecutable(string? path) =>
109109

110110
return null;
111111
}
112+
113+
public static List<string> GetExecutables(string path)
114+
{
115+
return Directory.GetFiles(path, "*.exe", SearchOption.AllDirectories).ToList();
116+
}
112117
}

GameLib.Demo/GameLib.Demo.Wpf/ViewModels/GameViewModel.cs

+15-4
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,24 @@ public static void OpenPath(string? path)
162162
}
163163

164164
[RelayCommand]
165-
public static void CopyToClipboard(string? text)
165+
public static void CopyToClipboard(object? obj)
166166
{
167-
if (string.IsNullOrEmpty(text))
167+
var copyText = string.Empty;
168+
169+
switch (obj)
168170
{
169-
return;
171+
case string text:
172+
copyText = text;
173+
break;
174+
case IEnumerable<string> list:
175+
copyText = string.Join("\n", list);
176+
break;
170177
}
171178

172-
Clipboard.SetText(text);
179+
if (string.IsNullOrEmpty(copyText))
180+
{
181+
return;
182+
}
183+
Clipboard.SetText(copyText);
173184
}
174185
}

GameLib.Demo/GameLib.Demo.Wpf/Views/GameView.xaml

+47-9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
<Setter Property="IsReadOnlyCaretVisible" Value="True" />
2828
</Style>
2929

30+
<Style TargetType="ListBox">
31+
<Setter Property="Width" Value="500" />
32+
<Setter Property="Height" Value="100" />
33+
34+
</Style>
35+
3036
<Style TargetType="Button">
3137
<Setter Property="Background" Value="#373737" />
3238
</Style>
@@ -441,20 +447,52 @@
441447
</StackPanel>
442448
<!--#endregion-->
443449

444-
<!--#region Working directory-->
450+
<!--#region Executables-->
445451
<TextBlock
446452
Grid.Row="15"
447453
Grid.Column="0"
448454
HorizontalAlignment="Right"
455+
VerticalAlignment="Top"
456+
Text="Addtl. executables: " />
457+
<ListBox
458+
Grid.Row="15"
459+
Grid.Column="2"
460+
VerticalAlignment="Center"
461+
ItemsSource="{Binding SelectedGame.Executables, Mode=OneWay}" />
462+
<StackPanel
463+
Grid.Row="15"
464+
Grid.Column="4"
465+
HorizontalAlignment="Left"
466+
VerticalAlignment="Top"
467+
Orientation="Horizontal">
468+
<Button
469+
Command="{Binding CopyToClipboardCommand}"
470+
CommandParameter="{Binding SelectedGame.Executables}"
471+
ToolTip="Copy to clipboard">
472+
<Image
473+
Width="20"
474+
Height="20"
475+
Margin="2"
476+
Source="/Resources/copy-white.png" />
477+
</Button>
478+
</StackPanel>
479+
480+
<!--#endregion-->
481+
482+
<!--#region Working directory-->
483+
<TextBlock
484+
Grid.Row="17"
485+
Grid.Column="0"
486+
HorizontalAlignment="Right"
449487
VerticalAlignment="Center"
450488
Text="Working directory: " />
451489
<TextBox
452-
Grid.Row="15"
490+
Grid.Row="17"
453491
Grid.Column="2"
454492
VerticalAlignment="Center"
455493
Text="{Binding SelectedGame.WorkingDir, Mode=OneWay}" />
456494
<StackPanel
457-
Grid.Row="15"
495+
Grid.Row="17"
458496
Grid.Column="4"
459497
HorizontalAlignment="Left"
460498
VerticalAlignment="Center"
@@ -485,18 +523,18 @@
485523

486524
<!--#region Launch string-->
487525
<TextBlock
488-
Grid.Row="17"
526+
Grid.Row="19"
489527
Grid.Column="0"
490528
HorizontalAlignment="Right"
491529
VerticalAlignment="Center"
492530
Text="Launch string: " />
493531
<TextBox
494-
Grid.Row="17"
532+
Grid.Row="19"
495533
Grid.Column="2"
496534
VerticalAlignment="Center"
497535
Text="{Binding SelectedGame.LaunchString, Mode=OneWay}" />
498536
<StackPanel
499-
Grid.Row="17"
537+
Grid.Row="19"
500538
Grid.Column="4"
501539
HorizontalAlignment="Left"
502540
VerticalAlignment="Center"
@@ -526,22 +564,22 @@
526564

527565
<!--#region IsRunning-->
528566
<TextBlock
529-
Grid.Row="19"
567+
Grid.Row="21"
530568
Grid.Column="0"
531569
HorizontalAlignment="Right"
532570
VerticalAlignment="Center"
533571
Text="Is running: " />
534572

535573
<Image
536-
Grid.Row="19"
574+
Grid.Row="21"
537575
Grid.Column="2"
538576
Width="24"
539577
Height="24"
540578
HorizontalAlignment="Left"
541579
Source="{Binding IsRunningLogo}" />
542580

543581
<StackPanel
544-
Grid.Row="19"
582+
Grid.Row="21"
545583
Grid.Column="4"
546584
HorizontalAlignment="Left"
547585
VerticalAlignment="Center"

GameLib.Plugin/GameLib.Plugin.BattleNet/BattleNetGameFactory.cs

+23-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public static IEnumerable<BattleNetGame> GetGames(ILauncher launcher, Cancellati
1919
.Where(game => game is not null)
2020
.Select(game => AddLauncherId(launcher, game))
2121
.Select(game => AddCatalogData(launcher, game, catalog))
22+
.Select(game => AddExecutables(launcher, game))
2223
.ToList()!;
2324
}
2425

@@ -31,6 +32,22 @@ private static BattleNetGame AddLauncherId(ILauncher launcher, BattleNetGame gam
3132
return game;
3233
}
3334

35+
/// <summary>
36+
/// Find executables within the install directory
37+
/// </summary>
38+
private static BattleNetGame AddExecutables(ILauncher launcher, BattleNetGame game)
39+
{
40+
if (launcher.LauncherOptions.SearchExecutables)
41+
{
42+
var executables = PathUtil.GetExecutables(game.InstallDir);
43+
44+
executables.AddRange(game.Executables);
45+
game.Executables = executables.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
46+
}
47+
48+
return game;
49+
}
50+
3451
/// <summary>
3552
/// Load local catalog data
3653
/// </summary>
@@ -122,11 +139,12 @@ private static BattleNetGame AddCatalogData(ILauncher launcher, BattleNetGame ga
122139
game.LaunchString = $"\"{launcher.Executable}\" --exec=\"launch {game.ProductCode}\"";
123140
}
124141

125-
var executable = catalogItem.Executables.FirstOrDefault(defaultValue: string.Empty);
126-
if (!string.IsNullOrEmpty(executable))
127-
{
128-
game.Executable = Path.Combine(game.InstallDir, executable);
129-
}
142+
game.Executables = catalogItem.Executables
143+
.Where(e => !string.IsNullOrEmpty(e))
144+
.Select(e => Path.Combine(game.InstallDir, e))
145+
.ToList();
146+
147+
game.Executable = game.Executables.FirstOrDefault(defaultValue: string.Empty);
130148

131149
return game;
132150
}

GameLib.Plugin/GameLib.Plugin.BattleNet/Model/BattleNetGame.cs

+1-13
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,21 @@ public class BattleNetGame : IGame
88
{
99
#region Interface implementations
1010
public string Id { get; internal set; } = string.Empty;
11-
1211
public Guid LauncherId { get; internal set; } = Guid.Empty;
13-
1412
public string Name { get; internal set; } = string.Empty;
15-
1613
public string InstallDir { get; internal set; } = string.Empty;
17-
1814
public string Executable { get; internal set; } = string.Empty;
19-
2015
public Icon? ExecutableIcon => PathUtil.GetFileIcon(Executable);
21-
16+
public IEnumerable<string> Executables { get; internal set; } = Enumerable.Empty<string>();
2217
public string WorkingDir { get; internal set; } = string.Empty;
23-
2418
public string LaunchString { get; internal set; } = string.Empty;
25-
2619
public DateTime InstallDate { get; internal set; } = DateTime.MinValue;
27-
2820
public bool IsRunning => ProcessUtil.IsProcessRunning(Executable);
2921
#endregion
3022

3123
public string ProductCode { get; internal set; } = string.Empty;
32-
3324
public string SpeechLanguage { get; internal set; } = string.Empty;
34-
3525
public string TextLanguage { get; internal set; } = string.Empty;
36-
3726
public string PlayRegion { get; internal set; } = string.Empty;
38-
3927
public string Version { get; internal set; } = string.Empty;
4028
}

GameLib.Plugin/GameLib.Plugin.Epic/EpicGameFactory.cs

+39-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public static IEnumerable<EpicGame> GetGames(ILauncher launcher, CancellationTok
2222
.Select(DeserializeManifest)
2323
.Where(game => game is not null)
2424
.Select(game => AddLauncherId(launcher, game!))
25+
.Select(game => AddExecutables(launcher, game!))
2526
.ToList()!;
2627
}
2728

@@ -34,6 +35,22 @@ private static EpicGame AddLauncherId(ILauncher launcher, EpicGame game)
3435
return game;
3536
}
3637

38+
/// <summary>
39+
/// Find executables within the install directory
40+
/// </summary>
41+
private static EpicGame AddExecutables(ILauncher launcher, EpicGame game)
42+
{
43+
if (launcher.LauncherOptions.SearchExecutables)
44+
{
45+
var executables = PathUtil.GetExecutables(game.InstallDir);
46+
47+
executables.AddRange(game.Executables);
48+
game.Executables = executables.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
49+
}
50+
51+
return game;
52+
}
53+
3754
/// <summary>
3855
/// Get the meta data directory from registry; if not found try to locate in Common Application data
3956
/// </summary>
@@ -81,9 +98,29 @@ private static EpicGame AddLauncherId(ILauncher launcher, EpicGame game)
8198
}
8299
catch { return null; }
83100

84-
var game = deserializedEpicGame.EpicGameBuilder();
101+
var game = new EpicGame()
102+
{
103+
Id = deserializedEpicGame.AppName,
104+
Name = deserializedEpicGame.DisplayName,
105+
InstallDir = PathUtil.Sanitize(deserializedEpicGame.InstallLocation) ?? string.Empty,
106+
WorkingDir = deserializedEpicGame.InstallLocation,
107+
InstallSize = deserializedEpicGame.InstallSize,
108+
Version = deserializedEpicGame.AppVersionString,
109+
};
110+
111+
if (PathUtil.IsExecutable(deserializedEpicGame.MainWindowProcessName))
112+
{
113+
game.Executable = Path.Combine(game.InstallDir, deserializedEpicGame.MainWindowProcessName);
114+
if (PathUtil.IsExecutable(deserializedEpicGame.MainWindowProcessName))
115+
{
116+
game.Executables = new List<string>() { Path.Combine(game.InstallDir, deserializedEpicGame.LaunchExecutable) };
117+
}
118+
}
119+
else if (PathUtil.IsExecutable(deserializedEpicGame.LaunchExecutable))
120+
{
121+
game.Executable = Path.Combine(game.InstallDir, deserializedEpicGame.LaunchExecutable);
122+
}
85123

86-
game.Executable = Path.Combine(PathUtil.Sanitize(game.InstallDir)!, game.Executable);
87124
game.LaunchString = $"com.epicgames.launcher://apps/{game.Id}?action=launch&silent=true";
88125
game.InstallDate = PathUtil.GetCreationTime(game.InstallDir) ?? DateTime.MinValue;
89126

GameLib.Plugin/GameLib.Plugin.Epic/Model/DeserializedEpicGame.cs

+1-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using Gamelib.Core.Util;
2-
using Newtonsoft.Json;
1+
using Newtonsoft.Json;
32

43
namespace GameLib.Plugin.Epic.Model;
54

@@ -118,15 +117,4 @@ public class DeserializedEpicGame
118117

119118
[JsonProperty("MainGameAppName")]
120119
public string MainGameAppName { get; set; } = string.Empty;
121-
122-
public EpicGame EpicGameBuilder() => new()
123-
{
124-
Id = AppName,
125-
Name = DisplayName,
126-
InstallDir = InstallLocation,
127-
Executable = PathUtil.IsExecutable(MainWindowProcessName) ? MainWindowProcessName : LaunchExecutable,
128-
WorkingDir = InstallLocation,
129-
InstallSize = InstallSize,
130-
Version = AppVersionString,
131-
};
132120
}

GameLib.Plugin/GameLib.Plugin.Epic/Model/EpicGame.cs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class EpicGame : IGame
1313
public string InstallDir { get; internal set; } = string.Empty;
1414
public string Executable { get; internal set; } = string.Empty;
1515
public Icon? ExecutableIcon => PathUtil.GetFileIcon(Executable);
16+
public IEnumerable<string> Executables { get; internal set; } = Enumerable.Empty<string>();
1617
public string WorkingDir { get; internal set; } = string.Empty;
1718
public string LaunchString { get; internal set; } = string.Empty;
1819
public DateTime InstallDate { get; internal set; } = DateTime.MinValue;

0 commit comments

Comments
 (0)