diff --git a/SPTInstaller/Controllers/InstallController.cs b/SPTInstaller/Controllers/InstallController.cs index 54cdfab..97782d7 100644 --- a/SPTInstaller/Controllers/InstallController.cs +++ b/SPTInstaller/Controllers/InstallController.cs @@ -1,5 +1,4 @@ using Serilog; -using SharpCompress; using SPTInstaller.CustomControls; using SPTInstaller.Interfaces; using SPTInstaller.Models; @@ -22,13 +21,18 @@ public class InstallController { _tasks = tasks; _preChecks = preChecks; - - _preChecks.ForEach(x => x.ReeevaluationRequested += (s, e) => + + foreach (var check in _preChecks) { - if (s is IPreCheck preCheck) + check.ReeevaluationRequested += (s, _) => { - Log.Information($"{preCheck.Name}: requested re-evaluation"); + if (s is not IPreCheck preCheck) + { + return; + } + Log.Information($"{preCheck.Name}: requested re-evaluation"); + if (_installRunning) { Log.Warning("Install is running, re-evaluation denied (how did you do this?)"); @@ -36,8 +40,8 @@ public class InstallController } RecheckRequested?.Invoke(this, null); - } - }); + }; + } } public async Task RunPreChecks() @@ -45,7 +49,10 @@ public class InstallController Log.Information("-<>--<>- Running PreChecks -<>--<>-"); var requiredResults = new List(); - _preChecks.ForEach(x => x.State = StatusSpinner.SpinnerState.Pending); + foreach (var check in _preChecks) + { + check.State = StatusSpinner.SpinnerState.Pending; + } foreach (var check in _preChecks) { diff --git a/SPTInstaller/Helpers/FileHelper.cs b/SPTInstaller/Helpers/FileHelper.cs index 48399f9..4b9a77d 100644 --- a/SPTInstaller/Helpers/FileHelper.cs +++ b/SPTInstaller/Helpers/FileHelper.cs @@ -126,28 +126,39 @@ public static class FileHelper } } - public static void StreamAssemblyResourceOut(string resourceName, string outputFilePath) + public static bool StreamAssemblyResourceOut(string resourceName, string outputFilePath) { - var assembly = Assembly.GetExecutingAssembly(); - - FileInfo outputFile = new FileInfo(outputFilePath); - - if (outputFile.Exists) + try { - outputFile.Delete(); + var assembly = Assembly.GetExecutingAssembly(); + + FileInfo outputFile = new FileInfo(outputFilePath); + + if (outputFile.Exists) + { + outputFile.Delete(); + } + + if (!outputFile.Directory.Exists) + { + Directory.CreateDirectory(outputFile.Directory.FullName); + } + + var resName = assembly.GetManifestResourceNames().First(x => x.EndsWith(resourceName)); + + using (FileStream fs = File.Create(outputFilePath)) + using (Stream s = assembly.GetManifestResourceStream(resName)) + { + s.CopyTo(fs); + } + + outputFile.Refresh(); + return outputFile.Exists; } - - if (!outputFile.Directory.Exists) + catch (Exception ex) { - Directory.CreateDirectory(outputFile.Directory.FullName); - } - - var resName = assembly.GetManifestResourceNames().First(x => x.EndsWith(resourceName)); - - using (FileStream fs = File.Create(outputFilePath)) - using (Stream s = assembly.GetManifestResourceStream(resName)) - { - s.CopyTo(fs); + Log.Fatal(ex, $"Failed to stream resource out: {resourceName}"); + return false; } } diff --git a/SPTInstaller/Helpers/ZipHelper.cs b/SPTInstaller/Helpers/ZipHelper.cs index 5b970f9..4fbbd7d 100644 --- a/SPTInstaller/Helpers/ZipHelper.cs +++ b/SPTInstaller/Helpers/ZipHelper.cs @@ -1,46 +1,34 @@ -using System.Linq; -using SharpCompress.Archives; -using SharpCompress.Archives.Zip; -using SharpCompress.Common; +using SevenZip; using SPTInstaller.Models; namespace SPTInstaller.Helpers; public static class ZipHelper { - public static Result Decompress(FileInfo ArchivePath, DirectoryInfo OutputFolderPath, IProgress progress = null) + public static Result Decompress(FileInfo archiveFile, DirectoryInfo outputDirectory, IProgress progress = null) { try { - OutputFolderPath.Refresh(); + using var archiveStream = archiveFile.OpenRead(); - if (!OutputFolderPath.Exists) OutputFolderPath.Create(); + var dllPath = Path.Join(DownloadCacheHelper.CachePath, "7z.dll"); + + SevenZipBase.SetLibraryPath(dllPath); - using var archive = ZipArchive.Open(ArchivePath); - var totalEntries = archive.Entries.Where(entry => !entry.IsDirectory); - var processedEntries = 0; + var extractor = new SevenZipExtractor(archiveStream); - foreach (var entry in totalEntries) + extractor.Extracting += (_, args) => { - entry.WriteToDirectory(OutputFolderPath.FullName, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); + progress.Report(args.PercentDone); + }; - processedEntries++; + extractor.ExtractArchive(outputDirectory.FullName); - if (progress != null) - { - progress.Report(Math.Floor(((double)processedEntries / totalEntries.Count()) * 100)); - } - } + outputDirectory.Refresh(); - OutputFolderPath.Refresh(); - - if (!OutputFolderPath.Exists) + if (!outputDirectory.Exists) { - return Result.FromError($"Failed to extract files: {ArchivePath.Name}"); + return Result.FromError($"Failed to extract files: {archiveFile.Name}"); } return Result.FromSuccess(); diff --git a/SPTInstaller/Installer Tasks/DownloadTask.cs b/SPTInstaller/Installer Tasks/DownloadTask.cs index 374f44e..375f154 100644 --- a/SPTInstaller/Installer Tasks/DownloadTask.cs +++ b/SPTInstaller/Installer Tasks/DownloadTask.cs @@ -35,7 +35,9 @@ public class DownloadTask : InstallerTaskBase var mirrorsList = JsonConvert.DeserializeObject>(File.ReadAllText(file.FullName)); if (mirrorsList == null) + { return Result.FromError("Failed to deserialize mirrors list"); + } foreach (var mirror in mirrorsList) { @@ -59,7 +61,7 @@ public class DownloadTask : InstallerTaskBase { SetStatus("Downloading Patcher", "Verifying cached patcher ...", progressStyle: ProgressStyle.Indeterminate); - if (DownloadCacheHelper.CheckCache("patcher.zip", _expectedPatcherHash, out var cacheFile)) + if (DownloadCacheHelper.CheckCache("patcher", _expectedPatcherHash, out var cacheFile)) { _data.PatcherZipInfo = cacheFile; Log.Information("Using cached file {fileName} - Hash: {hash}", _data.PatcherZipInfo.Name, _expectedPatcherHash); @@ -106,7 +108,7 @@ public class DownloadTask : InstallerTaskBase SetStatus("Downloading SPT-AKI", _data.AkiReleaseDownloadLink, 0); - _data.AkiZipInfo = await DownloadCacheHelper.GetOrDownloadFileAsync("sptaki.zip", _data.AkiReleaseDownloadLink, progress, _data.AkiReleaseHash); + _data.AkiZipInfo = await DownloadCacheHelper.GetOrDownloadFileAsync("sptaki", _data.AkiReleaseDownloadLink, progress, _data.AkiReleaseHash); if (_data.AkiZipInfo == null) { diff --git a/SPTInstaller/Installer Tasks/PreChecks/NetCore6PreCheck.cs b/SPTInstaller/Installer Tasks/PreChecks/Net8PreCheck.cs similarity index 65% rename from SPTInstaller/Installer Tasks/PreChecks/NetCore6PreCheck.cs rename to SPTInstaller/Installer Tasks/PreChecks/Net8PreCheck.cs index 856d457..f2474b1 100644 --- a/SPTInstaller/Installer Tasks/PreChecks/NetCore6PreCheck.cs +++ b/SPTInstaller/Installer Tasks/PreChecks/Net8PreCheck.cs @@ -7,18 +7,18 @@ using SPTInstaller.Helpers; namespace SPTInstaller.Installer_Tasks.PreChecks; -public class NetCore6PreCheck : PreCheckBase +public class Net8PreCheck : PreCheckBase { - public NetCore6PreCheck() : base(".Net Core 6 Desktop Runtime", true) + public Net8PreCheck() : base(".Net 8 Desktop Runtime", true) { } public override async Task CheckOperation() { - var minRequiredVersion = new Version("6.0.0"); + var minRequiredVersion = new Version("8.0.0"); string[] output; - var failedButtonText = "Download .Net Core 6 Desktop Runtime"; + var failedButtonText = "Download .Net 8 Desktop Runtime"; var failedButtonAction = () => { @@ -27,7 +27,7 @@ public class NetCore6PreCheck : PreCheckBase FileName = "cmd.exe", UseShellExecute = true, WindowStyle = ProcessWindowStyle.Hidden, - ArgumentList = { "/C", "start", "https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-6.0.4-windows-x64-installer" } + ArgumentList = { "/C", "start", "https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-8.0.2-windows-x64-installer" } }); }; @@ -37,7 +37,7 @@ public class NetCore6PreCheck : PreCheckBase if (!result.Succeeded) { - return PreCheckResult.FromError(result.Message + "\n\nYou most likely don't have .net 6 installed", failedButtonText, failedButtonAction); + return PreCheckResult.FromError(result.Message + "\n\nYou most likely don't have .net 8 installed", failedButtonText, failedButtonAction); } output = result.StdOut.Split("\r\n"); @@ -63,12 +63,12 @@ public class NetCore6PreCheck : PreCheckBase if (foundVersion >= minRequiredVersion) { - return PreCheckResult.FromSuccess($".Net Core {minRequiredVersion} Desktop Runtime or higher is installed.\n\nInstalled Version: {foundVersion}"); + return PreCheckResult.FromSuccess($".Net {minRequiredVersion} Desktop Runtime or higher is installed.\n\nInstalled Version: {foundVersion}"); } highestFoundVersion = foundVersion > highestFoundVersion ? foundVersion : highestFoundVersion; } - return PreCheckResult.FromError($".Net Core Desktop Runtime version {minRequiredVersion} or higher is required.\n\nHighest Version Found: {(highestFoundVersion > new Version("0.0.0") ? highestFoundVersion : "Not Found")}\n\nThis is required to play SPT, but you can install it later if and shouldn't affect the SPT install process.", failedButtonText, failedButtonAction); + return PreCheckResult.FromError($".Net Desktop Runtime version {minRequiredVersion} or higher is required.\n\nHighest Version Found: {(highestFoundVersion > new Version("0.0.0") ? highestFoundVersion : "Not Found")}\n\nThis is required to play SPT", failedButtonText, failedButtonAction); } } \ No newline at end of file diff --git a/SPTInstaller/Installer Tasks/SetupClientTask.cs b/SPTInstaller/Installer Tasks/SetupClientTask.cs index e62e2f1..0c2a610 100644 --- a/SPTInstaller/Installer Tasks/SetupClientTask.cs +++ b/SPTInstaller/Installer Tasks/SetupClientTask.cs @@ -28,6 +28,13 @@ public class SetupClientTask : InstallerTaskBase if (_data.PatchNeeded) { + SetStatus("Preparing 7z", "", null, ProgressStyle.Indeterminate); + + if (!FileHelper.StreamAssemblyResourceOut("7z.dll", Path.Join(DownloadCacheHelper.CachePath, "7z.dll"))) + { + return Result.FromError("Failed to prepare 7z"); + } + // extract patcher files SetStatus("Extrating Patcher", "", 0); diff --git a/SPTInstaller/Models/InstallerUpdateInfo.cs b/SPTInstaller/Models/InstallerUpdateInfo.cs index 176e79d..eeab3b9 100644 --- a/SPTInstaller/Models/InstallerUpdateInfo.cs +++ b/SPTInstaller/Models/InstallerUpdateInfo.cs @@ -61,7 +61,12 @@ public class InstallerUpdateInfo : ReactiveObject UpdateAvailable = false; var updater = new FileInfo(Path.Join(DownloadCacheHelper.CachePath, "update.ps1")); - FileHelper.StreamAssemblyResourceOut("update.ps1", updater.FullName); + + if (!FileHelper.StreamAssemblyResourceOut("update.ps1", updater.FullName)) + { + Log.Fatal("Failed to prepare update file"); + return; + } if (!updater.Exists) diff --git a/SPTInstaller/Models/Mirrors/Downloaders/HttpMirrorDownloader.cs b/SPTInstaller/Models/Mirrors/Downloaders/HttpMirrorDownloader.cs index 584fe1b..2a49364 100644 --- a/SPTInstaller/Models/Mirrors/Downloaders/HttpMirrorDownloader.cs +++ b/SPTInstaller/Models/Mirrors/Downloaders/HttpMirrorDownloader.cs @@ -10,7 +10,7 @@ public class HttpMirrorDownloader : MirrorDownloaderBase public override async Task Download(IProgress progress) { - var file = await DownloadCacheHelper.DownloadFileAsync("patcher.zip", MirrorInfo.Link, progress); + var file = await DownloadCacheHelper.DownloadFileAsync("patcher", MirrorInfo.Link, progress); if (file == null) return null; diff --git a/SPTInstaller/Models/Mirrors/Downloaders/MegaMirrorDownloader.cs b/SPTInstaller/Models/Mirrors/Downloaders/MegaMirrorDownloader.cs index 23212dd..bf1e343 100644 --- a/SPTInstaller/Models/Mirrors/Downloaders/MegaMirrorDownloader.cs +++ b/SPTInstaller/Models/Mirrors/Downloaders/MegaMirrorDownloader.cs @@ -23,7 +23,7 @@ public class MegaMirrorDownloader : MirrorDownloaderBase { using var megaDownloadStream = await megaClient.DownloadAsync(new Uri(MirrorInfo.Link), progress); - var file = await DownloadCacheHelper.DownloadFileAsync("patcher.zip", megaDownloadStream); + var file = await DownloadCacheHelper.DownloadFileAsync("patcher", megaDownloadStream); if (file == null) return null; diff --git a/SPTInstaller/Program.cs b/SPTInstaller/Program.cs index e546d45..c1bb4d9 100644 --- a/SPTInstaller/Program.cs +++ b/SPTInstaller/Program.cs @@ -44,7 +44,7 @@ internal class Program #if !TEST ServiceHelper.Register(); - ServiceHelper.Register(); + ServiceHelper.Register(); ServiceHelper.Register(); ServiceHelper.Register(); diff --git a/SPTInstaller/Resources/7z.dll b/SPTInstaller/Resources/7z.dll new file mode 100644 index 0000000..2ba9f27 Binary files /dev/null and b/SPTInstaller/Resources/7z.dll differ diff --git a/SPTInstaller/SPTInstaller.csproj b/SPTInstaller/SPTInstaller.csproj index 2726d59..6122a87 100644 --- a/SPTInstaller/SPTInstaller.csproj +++ b/SPTInstaller/SPTInstaller.csproj @@ -1,7 +1,7 @@  WinExe - net6.0 + net8.0 true enable true @@ -9,8 +9,8 @@ icon.ico Assets\icon.ico Debug;Release;TEST - 2.33 - 2.33 + 2.42 + 2.42 SPT-AKI @@ -23,6 +23,8 @@ + + @@ -42,7 +44,7 @@ - +