This repository has been archived by the owner on Jun 26, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 163
/
SteamFinder.cs
209 lines (179 loc) · 6.95 KB
/
SteamFinder.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace BeatSaberModManager.Dependencies
{
/// <summary>
/// Steam installation path and Steam games folder finder.
/// </summary>
class SteamFinder
{
public string SteamPath { get; private set; }
public string[] Libraries { get; private set; }
/// <summary>
/// Tries to find the Steam folder and its libraries on the system.
/// </summary>
/// <returns>Returns true if a valid Steam installation folder path was found.</returns>
public bool FindSteam()
{
SteamPath = null;
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
case PlatformID.WinCE:
SteamPath = FindWindowsSteamPath();
break;
default:
if (IsUnix())
SteamPath = FindUnixSteamPath();
break;
}
if (SteamPath == null)
return false;
return FindLibraries();
}
/// <summary>
/// Retrieves the game folder by reading the game's Steam manifest. The game needs to be marked as installed on Steam.
/// <para>Returns null if not found.</para>
/// </summary>
/// <param name="appId">The game's app id on Steam.</param>
/// <returns>The path to the game folder.</returns>
public string FindGameFolder(int appId)
{
if (Libraries == null)
throw new InvalidOperationException("Steam must be found first.");
foreach (var library in Libraries)
{
var gameManifestPath = GetManifestFilePath(library, appId);
if (gameManifestPath == null)
continue;
var gameFolderName = ReadInstallDirFromManifest(gameManifestPath);
if (gameFolderName == null)
continue;
return Path.Combine(library, "common", gameFolderName);
}
return null;
}
/// <summary>
/// Searches for a game directory that has the specified name in known libraries.
/// </summary>
/// <param name="gameFolderName">The game's folder name inside the Steam library.</param>
/// <returns>The game folders path in the libraries.</returns>
public IEnumerable<string> FindGameFolders(string gameFolderName)
{
if (Libraries == null)
throw new InvalidOperationException("Steam must be found first.");
gameFolderName = gameFolderName.ToLowerInvariant();
foreach (var library in Libraries)
{
var folder = Directory.EnumerateDirectories(library)
.FirstOrDefault(f => Path.GetFileName(f).ToLowerInvariant() == gameFolderName);
if (folder != null)
yield return folder;
}
}
bool FindLibraries()
{
var steamLibraries = new List<string>();
var steamDefaultLibrary = Path.Combine(SteamPath, "steamapps");
if (!Directory.Exists(steamDefaultLibrary))
return false;
steamLibraries.Add(steamDefaultLibrary);
/*
* Get library folders paths from libraryfolders.vdf
*
* Libraries are listed like this:
* "id" "library folder path"
*
* Examples:
* "1" "D:\\Games\\SteamLibraryOnD"
* "2" "E:\\Games\\steam_games"
*/
var regex = new Regex(@"""\d+""\s+""(.+)""");
var libraryFoldersFilePath = Path.Combine(steamDefaultLibrary, "libraryfolders.vdf");
if (File.Exists(libraryFoldersFilePath))
{
foreach (var line in File.ReadAllLines(libraryFoldersFilePath))
{
var match = regex.Match(line);
if (!match.Success)
continue;
var libPath = match.Groups[1].Value;
libPath = libPath.Replace("\\\\", "\\"); // unescape the backslashes
libPath = Path.Combine(libPath, "steamapps");
if (Directory.Exists(libPath))
steamLibraries.Add(libPath);
}
}
Libraries = steamLibraries.ToArray();
return true;
}
static string GetManifestFilePath(string libraryPath, int appId)
{
var manifestPath = Path.Combine(libraryPath, $"appmanifest_{appId}.acf");
if (File.Exists(manifestPath))
return manifestPath;
else
return null;
}
static string ReadInstallDirFromManifest(string manifestFilePath)
{
var regex = new Regex(@"""installdir""\s+""(.+)""");
foreach (var line in File.ReadAllLines(manifestFilePath))
{
var match = regex.Match(line);
if (!match.Success)
continue;
return match.Groups[1].Value;
}
return null;
}
static string FindWindowsSteamPath()
{
var regPath = Environment.Is64BitOperatingSystem
? @"SOFTWARE\Wow6432Node\Valve\Steam"
: @"SOFTWARE\Valve\Steam";
var subRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(regPath);
var path = subRegKey?.GetValue("InstallPath").ToString()
.Replace('/', '\\'); // not actually required, just for consistency's sake
if (Directory.Exists(path))
return path;
else
return null;
}
static string FindUnixSteamPath()
{
string path = null;
if (Directory.Exists(path = GetDefaultLinuxSteamPath())
|| Directory.Exists(path = GetDefaultMacOsSteamPath()))
{
return path;
}
return null;
}
static string GetDefaultLinuxSteamPath()
{
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Personal),
".local/share/Steam/"
);
}
static string GetDefaultMacOsSteamPath()
{
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Personal),
"Library/Application Support/Steam"
);
}
// https://stackoverflow.com/questions/5116977
static bool IsUnix()
{
var p = (int)Environment.OSVersion.Platform;
return p == 4 || p == 6 || p == 128;
}
}
}