-
Notifications
You must be signed in to change notification settings - Fork 4
/
Steam.cs
118 lines (104 loc) · 4.54 KB
/
Steam.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Win32;
namespace BuildTool
{
public static class Steam
{
private static readonly Regex steamJsonRegex = new Regex("\"(.*)\"\t*\"(.*)\"", RegexOptions.Compiled);
/// <summary>
/// Finds game install directory by iterating through all the steam game libraries configured and finding the appid
/// that matches.
/// </summary>
/// <param name="steamAppId"></param>
/// <returns></returns>
/// <exception cref="Exception">If steam is not installed or game could not be found.</exception>
public static SteamGameData FindGame(uint steamAppId)
{
var steamPath = (string) ReadRegistrySafe("Software\\Valve\\Steam", "SteamPath");
if (string.IsNullOrEmpty(steamPath))
{
try
{
steamPath = (string) ReadRegistrySafe(@"SOFTWARE\Valve\Steam",
"InstallPath",
RegistryHive.LocalMachine);
}
finally
{
if (string.IsNullOrEmpty(steamPath))
{
throw new Exception("Steam could not be found. Check if it is installed.");
}
}
}
var appsPath = Path.Combine(steamPath, "steamapps");
// Test main steamapps.
var game = GameDataFromAppManifest(Path.Combine(appsPath, $"appmanifest_{steamAppId}.acf"));
if (game == null)
{
// Test steamapps on other drives (as defined by Steam).
game = SearchAllInstallations(Path.Combine(appsPath, "libraryfolders.vdf"), steamAppId);
if (game == null)
{
throw new Exception($"Steam game with id {steamAppId} is not installed.");
}
}
return game;
}
private static SteamGameData SearchAllInstallations(
string libraryfoldersFile, uint appId)
{
if (!File.Exists(libraryfoldersFile)) return null;
// Turn contents of file into dictionary lookup.
var steamLibraryData = JsonAsDictionary(File.ReadAllText(libraryfoldersFile));
var steamLibraryIndex = 0;
while (true)
{
steamLibraryIndex++;
if (!steamLibraryData.TryGetValue(steamLibraryIndex.ToString(), out var steamLibraryPath)) return null;
var manifestFile = Path.Combine(steamLibraryPath, $"steamapps/appmanifest_{appId}.acf");
if (!File.Exists(manifestFile)) continue;
// Validate manifest is correct.
var game = GameDataFromAppManifest(manifestFile);
if (game.Id != appId) continue;
return game;
}
}
private static SteamGameData GameDataFromAppManifest(string manifestFile)
{
Dictionary<string, string> gameData = null;
try
{
gameData = JsonAsDictionary(File.ReadAllText(manifestFile));
}
catch (FileNotFoundException)
{
return null;
}
// Validate steam game data exists.
if (!gameData.TryGetValue("name", out var gameName)) return null;
if (!gameData.TryGetValue("appid", out var appidStr)) return null;
if (!uint.TryParse(appidStr, out var appId)) return null;
if (!gameData.TryGetValue("installdir", out var gameInstallFolderName)) return null;
var gameDir =
Path.GetFullPath(Path.Combine(Path.GetDirectoryName(manifestFile), "common", gameInstallFolderName));
if (!Directory.Exists(gameDir)) return null;
return new SteamGameData(appId, gameName, gameInstallFolderName, gameDir);
}
private static Dictionary<string, string> JsonAsDictionary(string json)
{
return steamJsonRegex.Matches(json)
.Cast<Match>()
.ToDictionary(m => m.Groups[1].Value.ToLowerInvariant(), m => m.Groups[2].Value);
}
private static object ReadRegistrySafe(string path, string key, RegistryHive hive = RegistryHive.CurrentUser)
{
using var subkey = RegistryKey.OpenBaseKey(hive, RegistryView.Registry32).OpenSubKey(path);
return subkey?.GetValue(key);
}
}
}