diff --git a/Features/Examine.cs b/Features/Examine.cs index e9408e7..f77ae6c 100644 --- a/Features/Examine.cs +++ b/Features/Examine.cs @@ -26,6 +26,7 @@ protected static bool ExaminedPrefix(ref bool __result) return false; // skip the original code and all other prefix methods } +#pragma warning disable IDE0060 [UsedImplicitly] protected static bool SinglePlayerInventoryControllerConstructorPrefix(Player player, Profile profile, ref bool examined) { @@ -37,6 +38,7 @@ protected static bool SinglePlayerInventoryControllerConstructorPrefix(Player pl examined = true; return true; } +#pragma warning restore IDE0060 protected override void UpdateWhenEnabled() { diff --git a/Installer/InstallCommand.cs b/Installer/InstallCommand.cs index 0dc7659..d781c21 100644 --- a/Installer/InstallCommand.cs +++ b/Installer/InstallCommand.cs @@ -66,6 +66,19 @@ public override async Task ExecuteAsync(CommandContext commandContext, Sett AnsiConsole.MarkupLine($"Target [green]EscapeFromTarkov ({installation.Version})[/] in [blue]{installation.Location.EscapeMarkup()}[/]."); + if (installation.UsingSptAki) + { + AnsiConsole.MarkupLine("[green][[SPT-AKI]][/] detected. Please make sure you have run the game at least once before installing the trainer."); + AnsiConsole.MarkupLine("SPT-AKI is patching binaries during the first run, and we [underline]need[/] to compile against those patched binaries."); + AnsiConsole.MarkupLine("If you install this trainer on stock binaries, we'll be unable to compile or the game will freeze at the startup screen."); + + if (installation.UsingSptAkiButNeverRun) + AnsiConsole.MarkupLine("[yellow]Warning: it seems that you have never run your SPT-AKI installation. You should quit now and rerun this installer once it's done.[/]"); + + if (!AnsiConsole.Confirm("Continue installation (yes I have run the game at least once) ?")) + return (int)ExitCode.Canceled; + } + const string features = "Features"; const string commands = "ConsoleCommands"; @@ -81,16 +94,6 @@ public override async Task ExecuteAsync(CommandContext commandContext, Sett return (int)ExitCode.CompilationFailed; } - if (installation.UsingSptAki) - { - AnsiConsole.MarkupLine("[green][[SPT-AKI]][/] detected. Please make sure you have run the game at least once before installing the trainer."); - AnsiConsole.MarkupLine("SPT-AKI is patching binaries during the first run, and we [underline]need[/] to compile against those patched binaries."); - AnsiConsole.MarkupLine("If you install this trainer on stock binaries, the game will freeze at the startup screen."); - - if (!AnsiConsole.Confirm("Continue installation (yes I have run the game at least once) ?")) - return (int)ExitCode.Canceled; - } - if (!CreateDll(installation, "NLog.EFT.Trainer.dll", dllPath => result.Compilation.Emit(dllPath, manifestResources: result.Resources))) return (int)ExitCode.CreateDllFailed; diff --git a/Installer/Installation.cs b/Installer/Installation.cs index b9475e3..56c53e0 100644 --- a/Installer/Installation.cs +++ b/Installer/Installation.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Runtime.Versioning; +using System.Text; using Microsoft.Win32; using Spectre.Console; @@ -14,8 +15,11 @@ internal class Installation { public Version Version { get; } public bool UsingSptAki { get; private set; } + public bool UsingSptAkiButNeverRun { get; private set; } public bool UsingBepInEx { get; private set; } public string Location { get; } + public string DisplayString { get; private set; } = string.Empty; + public string Data => Path.Combine(Location, "EscapeFromTarkov_Data"); public string Managed => Path.Combine(Data, "Managed"); public string BepInEx => Path.Combine(Location, "BepInEx"); @@ -56,10 +60,10 @@ public override int GetHashCode() installations = DiscoverInstallations() .Distinct() .ToList(); - }); - if (path is not null && TryDiscoverInstallation(path, out var installation)) - installations.Add(installation); + if (path is not null && TryDiscoverInstallation(path, out var installation)) + installations.Add(installation); + }); installations = [.. installations.Distinct().OrderBy(i => i.Location)]; @@ -72,11 +76,7 @@ public override int GetHashCode() var first = installations.First(); return AnsiConsole.Confirm($"Continue with [green]EscapeFromTarkov ({first.Version})[/] in [blue]{first.Location.EscapeMarkup()}[/] ?") ? first : null; default: - var prompt = new SelectionPrompt - { - Converter = i => i.Location.EscapeMarkup(), - Title = promptTitle - }; + var prompt = new SelectionPrompt { Title = promptTitle }; prompt.AddChoices(installations); return AnsiConsole.Prompt(prompt); } @@ -91,6 +91,10 @@ private static IEnumerable DiscoverInstallations() if (TryDiscoverInstallation(Path.GetDirectoryName(AppContext.BaseDirectory), out installation)) yield return installation; + // SPT-AKI default installation path + if (TryDiscoverInstallation(Path.Combine(Path.GetPathRoot(Environment.GetFolderPath(Environment.SpecialFolder.System))!, "SPT"), out installation)) + yield return installation; + using var hive = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32); using var eft = hive.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall\EscapeFromTarkov", false); @@ -143,8 +147,15 @@ private static bool TryDiscoverInstallation(string? path, [NotNullWhen(true)] ou var akiFolder = Path.Combine(path, "SPT_Data"); installation.UsingSptAki = Directory.Exists(akiFolder) || Directory.Exists(legacyAkiFolder); + + var battleye = Path.Combine(path, "BattlEye"); + var user = Path.Combine(path, "user"); + installation.UsingSptAkiButNeverRun = installation.UsingSptAki && (Directory.Exists(battleye) || !Directory.Exists(user)); + installation.UsingBepInEx = Directory.Exists(installation.BepInExPlugins); + installation.DisplayString = installation.ComputeDisplayString(); + return true; } catch (IOException) @@ -152,4 +163,21 @@ private static bool TryDiscoverInstallation(string? path, [NotNullWhen(true)] ou return false; } } + + private string ComputeDisplayString() + { + var sb = new StringBuilder(); + sb.Append($"{Location.EscapeMarkup()} - [[{Version}]] "); + sb.Append(UsingSptAki ? "[b]SPT-AKI[/] " : "Vanilla "); + + if (UsingSptAki && VersionChecker.IsVersionSupported(Version)) + sb.Append("[green](Supported)[/]"); + + return sb.ToString(); + } + + public override string ToString() + { + return DisplayString; + } } diff --git a/Installer/Installer.csproj b/Installer/Installer.csproj index 14b5c56..2939eda 100644 --- a/Installer/Installer.csproj +++ b/Installer/Installer.csproj @@ -17,7 +17,7 @@ Sebastien Lebreton https://github.com/sailro/EscapeFromTarkov-Trainer - 3.0.0.0 + 3.1.0.0 Sebastien Lebreton diff --git a/Installer/VersionChecker.cs b/Installer/VersionChecker.cs new file mode 100644 index 0000000..7ac4168 --- /dev/null +++ b/Installer/VersionChecker.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Spectre.Console; + +namespace Installer; + +internal class VersionChecker +{ + + private static readonly Dictionary _versions = []; + private static readonly HttpClient _client = new(); + private static readonly SemaphoreSlim _semaphore = new(1, 1); + + public static async Task IsVersionSupportedAsync(Version version) + { + await _semaphore.WaitAsync(); + + try + { + if (_versions.TryGetValue(version, out var supported)) + return supported; + + var branch = $"dev-{version}"; + var uri = new Uri($"https://github.com/sailro/EscapeFromTarkov-Trainer/tree/{branch}"); + var result = await _client.GetAsync(uri); + _versions[version] = result.IsSuccessStatusCode; + } + catch (Exception e) + { +#if DEBUG + AnsiConsole.WriteException(e); +#endif + + _versions[version] = false; + } + finally + { + _semaphore.Release(); + } + + return _versions[version]; + } + + public static bool IsVersionSupported(Version version) + { +#pragma warning disable VSTHRD002 + return IsVersionSupportedAsync(version) + .GetAwaiter() + .GetResult(); +#pragma warning restore VSTHRD002 + } +}