0
0
mirror of https://github.com/sp-tarkov/launcher.git synced 2025-02-13 08:50:43 -05:00

367 lines
13 KiB
C#
Raw Permalink Normal View History

2023-03-03 19:25:33 +00:00
/* GameStarter.cs
* License: NCSA Open Source License
*
2024-05-21 20:15:19 +01:00
* Copyright: SPT
2023-03-03 19:25:33 +00:00
* AUTHORS:
* waffle.lord
* reider123
*/
2024-05-21 20:15:19 +01:00
using SPT.Launcher.Helpers;
using SPT.Launcher.MiniCommon;
using SPT.Launcher.Models.Launcher;
2023-03-03 19:25:33 +00:00
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
2024-05-21 20:15:19 +01:00
using SPT.Launcher.Controllers;
using SPT.Launcher.Interfaces;
2023-03-03 19:25:33 +00:00
using System.Runtime.InteropServices;
using SPT.Launcher.Models.SPT;
using Newtonsoft.Json.Linq;
2023-03-03 19:25:33 +00:00
2024-05-21 20:15:19 +01:00
namespace SPT.Launcher
2023-03-03 19:25:33 +00:00
{
public class GameStarter
{
private readonly IGameStarterFrontend _frontend;
private readonly bool _showOnly;
private readonly string _originalGamePath;
private readonly string[] _excludeFromCleanup;
private const string registryInstall = @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\EscapeFromTarkov";
private const string registrySettings = @"Software\Battlestate Games\EscapeFromTarkov";
public GameStarter(IGameStarterFrontend frontend, string gamePath = null, string originalGamePath = null,
bool showOnly = false, string[] excludeFromCleanup = null)
{
_frontend = frontend;
_showOnly = showOnly;
_originalGamePath = originalGamePath ??= DetectOriginalGamePath();
_excludeFromCleanup = excludeFromCleanup ?? LauncherSettingsProvider.Instance.ExcludeFromCleanup;
}
private static string DetectOriginalGamePath()
{
// We can't detect the installed path on non-Windows
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return null;
var installLocation = Registry.LocalMachine.OpenSubKey(registryInstall, false)
?.GetValue("InstallLocation");
var info = (installLocation is string key) ? new DirectoryInfo(key) : null;
return info?.FullName;
2023-03-03 19:25:33 +00:00
}
public async Task<GameStarterResult> LaunchGame(ServerInfo server, AccountInfo account, string gamePath)
2023-03-03 19:25:33 +00:00
{
2024-02-05 16:06:28 -05:00
LogManager.Instance.Info(">>> Launching Game");
LogManager.Instance.Info($">>> Account: {account.username}");
LogManager.Instance.Info($">>> Server : {server.backendUrl}");
2023-03-03 19:25:33 +00:00
// setup directories
if (IsInstalledInLive())
{
2024-02-05 16:06:28 -05:00
LogManager.Instance.Error("[LaunchGame] Installed in Live :: YES");
2023-03-03 19:25:33 +00:00
return GameStarterResult.FromError(-1);
}
// Confirm core.dll version matches version server is running
if (IsCoreDllVersionMismatched(gamePath))
{
LogManager.Instance.Error("[LaunchGame] Core dll mismatch :: FAILED");
return GameStarterResult.FromError(-8);
}
2024-02-05 16:06:28 -05:00
LogManager.Instance.Info("[LaunchGame] Installed in Live :: NO");
LogManager.Instance.Info("[LaunchGame] Setup Game Files ...");
SetupGameFiles(gamePath);
2023-03-03 19:25:33 +00:00
if (!ValidationUtil.Validate())
{
2024-02-05 16:06:28 -05:00
LogManager.Instance.Error("[LaunchGame] Game Validation :: FAILED");
2023-03-03 19:25:33 +00:00
return GameStarterResult.FromError(-2);
}
2024-02-05 16:06:28 -05:00
LogManager.Instance.Info("[LaunchGame] Game Validation :: OK");
2023-03-03 19:25:33 +00:00
if (account.wipe)
{
2024-02-05 16:06:28 -05:00
LogManager.Instance.Info("[LaunchGame] Wipe profile requested");
RemoveProfileRegistryKeys(account.id);
2023-03-03 19:25:33 +00:00
CleanTempFiles();
}
// check game path
var clientExecutable = Path.Join(gamePath, "EscapeFromTarkov.exe");
2023-03-03 19:25:33 +00:00
if (!File.Exists(clientExecutable))
{
2024-02-05 16:06:28 -05:00
LogManager.Instance.Error("[LaunchGame] Valid Game Path :: FAILED");
LogManager.Instance.Error($"Could not find {clientExecutable}");
2023-03-03 19:25:33 +00:00
return GameStarterResult.FromError(-6);
}
2024-02-05 16:06:28 -05:00
LogManager.Instance.Info("[LaunchGame] Valid Game Path :: OK");
2023-03-03 19:25:33 +00:00
// apply patches
ProgressReportingPatchRunner patchRunner = new ProgressReportingPatchRunner(gamePath);
2023-03-03 19:25:33 +00:00
try
{
await _frontend.CompletePatchTask(patchRunner.PatchFiles());
}
catch (TaskCanceledException)
{
2024-02-05 16:06:28 -05:00
LogManager.Instance.Error("[LaunchGame] Applying Patch :: FAILED");
2023-03-03 19:25:33 +00:00
return GameStarterResult.FromError(-4);
}
2024-02-05 16:06:28 -05:00
LogManager.Instance.Info("[LaunchGame] Applying Patch :: OK");
2023-03-03 19:25:33 +00:00
//start game
var args =
$"-force-gfx-jobs native -token={account.id} -config={Json.Serialize(new ClientConfig(server.backendUrl))}";
if (_showOnly)
{
Console.WriteLine($"{clientExecutable} {args}");
2024-02-05 16:06:28 -05:00
LogManager.Instance.Info("[LaunchGame] NOOP :: show only");
2023-03-03 19:25:33 +00:00
}
else
{
var clientProcess = new ProcessStartInfo(clientExecutable)
{
Arguments = args,
UseShellExecute = false,
WorkingDirectory = gamePath,
2023-03-03 19:25:33 +00:00
};
2024-05-30 11:55:35 -04:00
try
{
Process.Start(clientProcess);
LogManager.Instance.Info("[LaunchGame] Game process started");
}
catch (Exception ex)
{
LogManager.Instance.Exception(ex);
return GameStarterResult.FromError(-7);
}
2023-03-03 19:25:33 +00:00
}
return GameStarterResult.FromSuccess();
}
bool IsInstalledInLive()
{
var isInstalledInLive = false;
try
{
var files = new FileInfo[]
{
2024-05-21 20:15:19 +01:00
// SPT files
new FileInfo(Path.Combine(_originalGamePath, @"SPT.Launcher.exe")),
new FileInfo(Path.Combine(_originalGamePath, @"SPT.Server.exe")),
2023-03-03 19:25:33 +00:00
// bepinex files
new FileInfo(Path.Combine(_originalGamePath, @"doorstep_config.ini")),
new FileInfo(Path.Combine(_originalGamePath, @"winhttp.dll")),
// licenses
new FileInfo(Path.Combine(_originalGamePath, @"LICENSE-BEPINEX.txt")),
new FileInfo(Path.Combine(_originalGamePath, @"LICENSE-ConfigurationManager.txt")),
new FileInfo(Path.Combine(_originalGamePath, @"LICENSE-Launcher.txt")),
new FileInfo(Path.Combine(_originalGamePath, @"LICENSE-Modules.txt")),
new FileInfo(Path.Combine(_originalGamePath, @"LICENSE-Server.txt"))
};
var directories = new DirectoryInfo[]
{
2024-05-21 20:15:19 +01:00
new DirectoryInfo(Path.Combine(_originalGamePath, @"SPT_Data")),
2023-03-03 19:25:33 +00:00
new DirectoryInfo(Path.Combine(_originalGamePath, @"BepInEx"))
};
foreach (var file in files)
{
if (File.Exists(file.FullName))
{
File.Delete(file.FullName);
2024-02-05 16:06:28 -05:00
LogManager.Instance.Warning($"File removed :: found in live dir: {file.FullName}");
2023-03-03 19:25:33 +00:00
isInstalledInLive = true;
}
}
foreach (var directory in directories)
{
if (Directory.Exists(directory.FullName))
{
RemoveFilesRecurse(directory);
2024-02-05 16:06:28 -05:00
LogManager.Instance.Warning($"Directory removed :: found in live dir: {directory.FullName}");
2023-03-03 19:25:33 +00:00
isInstalledInLive = true;
}
}
}
catch (Exception ex)
{
LogManager.Instance.Exception(ex);
}
return isInstalledInLive;
}
static bool IsCoreDllVersionMismatched(string gamePath)
{
try
{
var serverVersion = new SPTVersion(ServerManager.GetVersion());
2024-07-12 15:21:43 -04:00
var coreDllVersionInfo = FileVersionInfo.GetVersionInfo(Path.Join(gamePath, @"\BepinEx\plugins\spt", "spt-core.dll"));
var dllVersion = new SPTVersion(coreDllVersionInfo.FileVersion);
LogManager.Instance.Info($"[LaunchGame] spt-core.dll version: {dllVersion}");
// Edge case, running on locally built modules dlls, ignore check and return ok
if (dllVersion.Major == 1) return false;
// check 'X'.x.x
if (serverVersion.Major != dllVersion.Major) return true;
// check x.'X'.x
if (serverVersion.Minor != dllVersion.Minor) return true;
// check x.x.'X'
2024-07-13 19:01:49 +01:00
if (serverVersion.Build != dllVersion.Build) return true;
return false; // Versions match, hooray
}
catch (Exception ex)
{
LogManager.Instance.Exception(ex);
}
return true;
}
void SetupGameFiles(string gamePath)
2023-03-03 19:25:33 +00:00
{
var files = new []
{
GetFileForCleanup("BattlEye", gamePath),
GetFileForCleanup("Logs", gamePath),
GetFileForCleanup("ConsistencyInfo", gamePath),
GetFileForCleanup("EscapeFromTarkov_BE.exe", gamePath),
GetFileForCleanup("Uninstall.exe", gamePath),
GetFileForCleanup("UnityCrashHandler64.exe", gamePath),
GetFileForCleanup("WinPixEventRuntime.dll", gamePath)
2023-03-03 19:25:33 +00:00
};
foreach (var file in files)
{
if (file == null)
{
continue;
}
if (Directory.Exists(file))
{
RemoveFilesRecurse(new DirectoryInfo(file));
}
if (File.Exists(file))
{
File.Delete(file);
}
}
}
private string GetFileForCleanup(string fileName, string gamePath)
2023-03-03 19:25:33 +00:00
{
if (_excludeFromCleanup.Contains(fileName))
{
LogManager.Instance.Info($"Excluded {fileName} from file cleanup");
return null;
}
return Path.Combine(gamePath, fileName);
2023-03-03 19:25:33 +00:00
}
/// <summary>
/// Remove the SPT JSON-based registry keys associated with the given profile ID
2023-03-03 19:25:33 +00:00
/// </summary>
public void RemoveProfileRegistryKeys(string profileId)
2023-03-03 19:25:33 +00:00
{
var registryFile = new FileInfo(Path.Combine(Environment.CurrentDirectory, "user\\sptRegistry\\registry.json"));
2023-03-03 19:25:33 +00:00
if (!registryFile.Exists)
2023-03-03 19:25:33 +00:00
{
return;
2023-03-03 19:25:33 +00:00
}
JObject registryData = JObject.Parse(File.ReadAllText(registryFile.FullName));
// Find any property that has a key containing the profileId, and remove it
var propsToRemove = registryData.Properties().Where(prop => prop.Name.Contains(profileId, StringComparison.CurrentCultureIgnoreCase)).ToList();
propsToRemove.ForEach(prop => prop.Remove());
File.WriteAllText(registryFile.FullName, registryData.ToString());
2023-03-03 19:25:33 +00:00
}
/// <summary>
/// Clean the temp folder
/// </summary>
/// <returns>returns true if the temp folder was cleaned succefully or doesn't exist. returns false if something went wrong.</returns>
public bool CleanTempFiles()
{
2024-07-07 09:01:27 -04:00
var rootdir = new DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "user\\sptappdata"));
2023-03-03 19:25:33 +00:00
if (!rootdir.Exists)
{
return true;
}
return RemoveFilesRecurse(rootdir);
}
bool RemoveFilesRecurse(DirectoryInfo basedir)
{
2024-02-05 16:06:28 -05:00
LogManager.Instance.Info($"Recursive Removal: {basedir}");
2023-03-03 19:25:33 +00:00
if (!basedir.Exists)
{
return true;
}
try
{
// remove subdirectories
foreach (var dir in basedir.EnumerateDirectories())
{
RemoveFilesRecurse(dir);
}
// remove files
var files = basedir.GetFiles();
foreach (var file in files)
{
file.IsReadOnly = false;
file.Delete();
}
// remove directory
basedir.Delete();
}
catch (Exception ex)
{
LogManager.Instance.Exception(ex);
return false;
}
return true;
}
}
}