-
Notifications
You must be signed in to change notification settings - Fork 20
/
GameInstance.cs
483 lines (441 loc) · 18.8 KB
/
GameInstance.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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
using Fo76ini.Interface;
using Fo76ini.Properties;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Xml.Linq;
namespace Fo76ini.Profiles
{
public enum GameEdition
{
Unknown = 0,
Steam = 2,
SteamPTS = 5,
Xbox = 4,
MSStore = 4,
BethesdaNet = 1,
BethesdaNetPTS = 3
}
public enum LaunchOption
{
OpenURL = 0, // Launch through Steam or Xbox
RunExec = 1 // Run executable directly
}
/// <summary>
/// Represents a game installation. Contains information such as path and executable name.
/// </summary>
public class GameInstance
{
public string Title = "Untitled";
public GameEdition Edition = GameEdition.Unknown;
public string GamePath = "";
private string modsPath = "";
public string ModsPath
{
get
{
if (modsPath == "")
return GamePath;
return modsPath;
}
set
{
modsPath = value;
}
}
public string ExecutableName = "Fallout76.exe";
public string IniPrefix = "Fallout76";
public string IniParentPath = IniFiles.DefaultParentPath;
public string ExecParameters = "";
public string LauncherURL = "";
public LaunchOption PreferredLaunchOption = LaunchOption.OpenURL;
/// <summary>
/// Sets the default settings (such as executable name, ini prefix, and launcher url) for the game edition.
/// </summary>
public void SetDefaultSettings(GameEdition edition)
{
this.IniParentPath = IniFiles.DefaultParentPath;
this.IniPrefix = "Fallout76";
this.ExecutableName = "Fallout76.exe";
this.PreferredLaunchOption = LaunchOption.OpenURL;
switch (edition)
{
case GameEdition.Steam:
this.LauncherURL = "steam:https://run/1151340";
break;
case GameEdition.SteamPTS:
this.LauncherURL = "steam:https://run/1836200";
break;
case GameEdition.Xbox:
this.ExecutableName = "Project76_GamePass.exe";
this.IniPrefix = "Project76";
/*
* Store link: @"ms-windows-store:https://pdp/?ProductId=9nkgnmnk3k3z"
* Launch URL: @"shell:appsfolder\BethesdaSoftworks.Fallout76-PC_3275kfvn8vcwc!Fallout76"
*
* Found a solution to launch the Xbox version of Fallout 76:
* https://stackoverflow.com/questions/32074404/launching-windows-10-store-apps
* https://stackoverflow.com/a/67156442
*
* Enter in PowerShell:
* PS C:\> Get-StartApps
* ^ The above will return a list:
*
* Name AppID
* ---- -----
* ...
* Fallout 76 BethesdaSoftworks.Fallout76-PC_3275kfvn8vcwc!Fallout76
*
* To start the app, enter in CMD:
* C:\> explorer shell:appsfolder\BethesdaSoftworks.Fallout76-PC_3275kfvn8vcwc!Fallout76
*
* This also works with Process.Start(@"shell:appsfolder\BethesdaSoftworks.Fallout76-PC_3275kfvn8vcwc!Fallout76");
*/
this.LauncherURL = @"shell:appsfolder\BethesdaSoftworks.Fallout76-PC_3275kfvn8vcwc!Fallout76";
break;
case GameEdition.BethesdaNet:
this.LauncherURL = "bethesdanet:https://run/20";
break;
case GameEdition.BethesdaNetPTS:
this.LauncherURL = "bethesdanet:https://run/57";
break;
default:
this.LauncherURL = "";
this.PreferredLaunchOption = LaunchOption.RunExec;
break;
}
}
public XElement Serialize ()
{
XElement xmlGameInstance = new XElement("Game",
new XElement("Title", Title),
new XElement("InstallationPath", GamePath),
new XElement("ModsPath", ModsPath),
new XElement("ExecutableName", ExecutableName),
new XElement("ExecParameters", ExecParameters),
new XElement("LauncherURL", LauncherURL),
new XElement("IniPrefix", IniPrefix),
new XElement("IniPath", IniParentPath),
new XElement("GameEdition", Edition.ToString()),
new XElement("LaunchOption", PreferredLaunchOption.ToString())
);
return xmlGameInstance;
}
public static GameInstance Deserialize (XElement xmlGameInstance)
{
GameInstance game = new GameInstance();
game.Title = xmlGameInstance.Element("Title").Value;
game.GamePath = xmlGameInstance.Element("InstallationPath").Value;
game.ExecutableName = xmlGameInstance.Element("ExecutableName").Value;
game.ExecParameters = xmlGameInstance.Element("ExecParameters").Value;
game.LauncherURL = xmlGameInstance.Element("LauncherURL").Value;
game.IniPrefix = xmlGameInstance.Element("IniPrefix").Value;
if (xmlGameInstance.Element("ModsPath") != null)
game.ModsPath = xmlGameInstance.Element("ModsPath").Value;
if (xmlGameInstance.Element("IniPath") != null)
game.IniParentPath = xmlGameInstance.Element("IniPath").Value;
if (!game.ValidateIniPath())
game.IniParentPath = IniFiles.DefaultParentPath;
if (Enum.TryParse(xmlGameInstance.Element("GameEdition").Value, out GameEdition edition))
game.Edition = edition;
if (Enum.TryParse(xmlGameInstance.Element("LaunchOption").Value, out LaunchOption launchOption))
game.PreferredLaunchOption = launchOption;
return game;
}
/// <summary>
/// Starts the game using the preferred launch option.
/// </summary>
public void LaunchGame()
{
LaunchGame(this.PreferredLaunchOption);
}
/// <summary>
/// Starts the game using the passed on launch option.
/// </summary>
/// <param name="option">Whether to run the executable or open the launcher url.</param>
public void LaunchGame(LaunchOption option)
{
switch (option)
{
case LaunchOption.OpenURL:
try
{
Process.Start(this.LauncherURL);
}
catch (Exception ex)
{
MsgBox.Show("Couldn't start game", $"Please make sure to provide a valid 'Launcher URL'.\n\n{ex.GetType()}: {ex.Message}", MessageBoxIcon.Error);
}
break;
case LaunchOption.RunExec:
try
{
Process pr = new Process();
pr.StartInfo.FileName = Path.Combine(this.GamePath, this.ExecutableName);
pr.StartInfo.WorkingDirectory = this.GamePath;
pr.StartInfo.Arguments = this.ExecParameters;
pr.StartInfo.UseShellExecute = false;
pr.Start();
}
catch (Exception ex)
{
MsgBox.Show("Couldn't start game", $"Please make sure that the game path and executable name are correct.\n\n{ex.GetType()}: {ex.Message}", MessageBoxIcon.Error);
}
break;
}
}
public static bool ValidateIniPath(string path)
{
return
path != null &&
path.Trim().Length > 0 &&
Directory.Exists(path);
}
public bool ValidateIniPath()
{
return ValidateIniPath(IniParentPath);
}
/// <summary>
/// Checks whether the passed on game path is valid.
/// </summary>
public static bool ValidateGamePath(string path)
{
return
path != null &&
path.Trim().Length > 0 &&
Directory.Exists(path) &&
Directory.Exists(Path.Combine(path, "Data")) &&
File.Exists(Path.Combine(path, "Data", "SeventySix.esm"));
}
/// <summary>
/// Checks whether the current game path is valid.
/// </summary>
public bool ValidateGamePath()
{
return ValidateGamePath(GamePath);
}
/// <summary>
/// Checks whether the passed on mods path is valid.
/// </summary>
public static bool ValidateModsPath(string path)
{
// TODO!
return
path != null &&
path.Trim().Length > 0 &&
Directory.Exists(path);
}
/// <summary>
/// Checks whether the current mods path is valid.
/// </summary>
public bool ValidateModsPath()
{
return ValidateModsPath(ModsPath);
}
public static string AutoDetectGamePath()
{
/*
* I could totally search through every single folder on a user's computer, but that would take way too long. So, I'll take shortcuts.
* This is not about to find a path for every user 100% of the time, but an attempt to find a path for MOST users in the shortest amount of time.
* If it can't find the path, the user likely knows enough about their computer to find it themselves. Even if it's a bit inconvenient.
*/
// Search every drive:
foreach (DriveInfo d in DriveInfo.GetDrives())
{
// Only search fixed drives:
if (d.DriveType != DriveType.Fixed)
continue;
// Search for "default" paths that are the most common:
string steamDefaultPath = Path.Combine(d.Name, @"Program Files (x86)\Steam\steamapps\common\Fallout76");
if (GameInstance.ValidateGamePath(steamDefaultPath))
{
switch (MsgBox.Get("gamePathAutoDetectPathFound").FormatText(steamDefaultPath).Show(MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
{
case DialogResult.Yes:
return steamDefaultPath;
case DialogResult.Cancel:
return null;
}
}
// Bethesda.net launcher - no longer in use
/*
string bethNetDefaultPath = Path.Combine(d.Name, @"Program Files (x86)\Bethesda.net Launcher\games\Fallout76");
if (GameInstance.ValidateGamePath(bethNetDefaultPath))
{
switch (MsgBox.Get("gamePathAutoDetectPathFound").FormatText(bethNetDefaultPath).Show(MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
{
case DialogResult.Yes:
return bethNetDefaultPath;
case DialogResult.Cancel:
return null;
}
}
*/
// Old Xbox default path
string xboxModifiablePath = Path.Combine(d.Name, @"Program Files\ModifiableWindowsApps\Fallout 76");
if (GameInstance.ValidateGamePath(xboxModifiablePath))
{
switch (MsgBox.Get("gamePathAutoDetectPathFound").FormatText(xboxModifiablePath).Show(MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
{
case DialogResult.Yes:
return xboxModifiablePath;
case DialogResult.Cancel:
return null;
}
}
// New Xbox default path
string xboxDefaultPath = Path.Combine(d.Name, @"XboxGames\Fallout 76\Content");
if (GameInstance.ValidateGamePath(xboxDefaultPath))
{
switch (MsgBox.Get("gamePathAutoDetectPathFound").FormatText(xboxDefaultPath).Show(MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
{
case DialogResult.Yes:
return xboxDefaultPath;
case DialogResult.Cancel:
return null;
}
}
// When you create a library on a drive through Steam's
string steamLibraryPath = Path.Combine(d.Name, @"SteamLibrary\steamapps\common\Fallout76");
if (GameInstance.ValidateGamePath(steamLibraryPath))
{
switch (MsgBox.Get("gamePathAutoDetectPathFound").FormatText(steamLibraryPath).Show(MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
{
case DialogResult.Yes:
return steamLibraryPath;
case DialogResult.Cancel:
return null;
}
}
// Search every top-level folder on the drive:
foreach (string path in Directory.EnumerateDirectories(d.Name))
{
if (GameInstance.ValidateGamePath(path))
{
switch (MsgBox.Get("gamePathAutoDetectPathFound").FormatText(path).Show(MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
{
case DialogResult.Yes:
return path;
case DialogResult.Cancel:
return null;
}
}
// Search for a steamapps folder:
string steamSubDirPath = Path.Combine(path, @"steamapps\common\Fallout76");
if (GameInstance.ValidateGamePath(steamSubDirPath))
{
switch (MsgBox.Get("gamePathAutoDetectPathFound").FormatText(steamSubDirPath).Show(MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
{
case DialogResult.Yes:
return steamSubDirPath;
case DialogResult.Cancel:
return null;
}
}
// New Xbox path:
string xboxSubDirPath = Path.Combine(d.Name, @"Fallout 76\Content");
if (GameInstance.ValidateGamePath(xboxSubDirPath))
{
switch (MsgBox.Get("gamePathAutoDetectPathFound").FormatText(xboxSubDirPath).Show(MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
{
case DialogResult.Yes:
return xboxSubDirPath;
case DialogResult.Cancel:
return null;
}
}
}
}
return null;
}
public Bitmap Get24pxBitmap()
{
return Get24pxBitmap(this.Edition);
}
public static Bitmap Get24pxBitmap(GameEdition edition)
{
switch (edition)
{
case GameEdition.Steam:
case GameEdition.SteamPTS:
return Resources.steam_24px;
case GameEdition.BethesdaNet:
case GameEdition.BethesdaNetPTS:
return Resources.bethesda_24;
case GameEdition.Xbox:
return Resources.xbox_24;
default:
return Resources.help_24;
}
}
public Bitmap Get128pxBitmap()
{
return Get128pxBitmap(this.Edition);
}
public static Bitmap Get128pxBitmap(GameEdition edition)
{
switch (edition)
{
case GameEdition.Steam:
case GameEdition.SteamPTS:
return Resources.steam;
case GameEdition.BethesdaNet:
return Resources.bethesda;
case GameEdition.BethesdaNetPTS:
return Resources.bethesda_pts;
case GameEdition.Xbox:
//return Resources.msstore;
return Resources.xbox;
default:
return Resources.help_128;
}
}
public Bitmap Get128pxHoverBitmap()
{
return Get128pxHoverBitmap(this.Edition);
}
public static Bitmap Get128pxHoverBitmap(GameEdition edition)
{
switch (edition)
{
case GameEdition.Steam:
return Resources.steam_hover;
case GameEdition.SteamPTS:
return Resources.steam_hover;
case GameEdition.BethesdaNet:
return Resources.bethesda_hover;
case GameEdition.BethesdaNetPTS:
return Resources.bethesda_pts_hover;
case GameEdition.Xbox:
//return Resources.msstore_hover;
return Resources.xbox_hover;
default:
return Resources.help_128_hover;
}
}
public string GetCaption()
{
return GetCaption(this.Edition);
}
public static string GetCaption(GameEdition edition)
{
switch (edition)
{
case GameEdition.Steam:
return "Steam";
case GameEdition.SteamPTS:
return "Steam (PTS)";
case GameEdition.BethesdaNet:
return "Bethesda.net";
case GameEdition.BethesdaNetPTS:
return "Bethesda.net (PTS)";
case GameEdition.Xbox:
return "Xbox";
default:
return Localization.GetString("unknown");
}
}
}
}