commit aceb8cf4e318b68b03bebd064bbc772253f6b13c Author: CWX Date: Fri May 13 22:41:15 2022 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51ef1cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +## SPTinstaller +*.exe +*.zip +bin/ +obj/ +*.editorconfig + +## visual studio +.vs +.idea +slnx.sqlite +slnx-journal.sqlite + +## nodejs +node_modules +node.exe +package-lock.json + +## windows +desktop.ini diff --git a/Aki.Asset/icon.ico b/Aki.Asset/icon.ico new file mode 100644 index 0000000..7fda173 Binary files /dev/null and b/Aki.Asset/icon.ico differ diff --git a/Aki.Core/Program.cs b/Aki.Core/Program.cs new file mode 100644 index 0000000..7ad6803 --- /dev/null +++ b/Aki.Core/Program.cs @@ -0,0 +1,127 @@ +using System.IO; +using System; +using System.Diagnostics; +using System.Threading; +using Installer.Aki.Helper; + +namespace Installer.Aki.Core +{ + //TODO: + // delete patcher zip and aki zip + + public static class SPTinstaller + { + private static string patchRef; + private static string akiRef; + private static DirectoryInfo dir; + + static void Main(string[] args) + { + string gamePath = GameHelper.DetectOriginalGamePath(); + + if (PatcherCheck(gamePath, out patchRef)) + { + LogHelper.Info($"Correct Zip for Patcher Present: {patchRef}"); + } + else + { + LogHelper.Error("Patcher zip is Incorrect or missing"); + LogHelper.Error("Press enter to close the app"); + Console.ReadKey(); + Environment.Exit(0); + } + + if (AkiCheck(out akiRef)) + { + LogHelper.Info($"Correct Zip for SPT-AKI Present: {akiRef}"); + } + else + { + LogHelper.Error("SPT-AKI zip is Incorrect or missing"); + LogHelper.Error("Press enter to close the app"); + Console.ReadKey(); + Environment.Exit(0); + } + + // checks for input to copy game files + LogHelper.User("PLEASE PRESS ENTER TO COPY GAME FILES!"); + Console.ReadKey(); + + // copies and pastes EFT to AKI installer test folder + FileHelper.CopyDirectory(gamePath, Environment.CurrentDirectory, true); + LogHelper.User("GAME HAS BEEN COPIED, PRESS ENTER TO EXTRACT PATCHER!"); + Console.ReadKey(); + + // extracts patcher and moves out inner folders + ZipHelper.Decompress(patchRef, Environment.CurrentDirectory); + FileHelper.FindFolder(patchRef, out dir); + FileHelper.CopyDirectory(dir.FullName, Environment.CurrentDirectory, true); + if (dir.Exists) + { + dir.Delete(true); + dir.Refresh(); + if (dir.Exists) + { + LogHelper.Error("unable to delete patcher folder"); + LogHelper.Error($"please delete folder called {dir.FullName}"); + } + } + + // starts patcher and checks for user input to exit patcher and proceed + LogHelper.User("PATCHER HAS BEEN EXTRACTED, STARTING PATCHER!"); + ProcessHelper patcherProcess = new ProcessHelper(); + patcherProcess.StartProcess(Path.Join(Environment.CurrentDirectory + "/patcher.exe"), Environment.CurrentDirectory); + LogHelper.User("PATCHER HAS BEEN STARTED, TYPE YES ONCE THE PATCHER IS COMPLETE!"); + var complete = Console.ReadLine(); + + // waiting for user to enter "yes", if something else is entered do while loop + while (!string.Equals(complete, "yes", StringComparison.OrdinalIgnoreCase)) + { + LogHelper.Warning("YOU DIDNT TYPE YES, IF SOMETHING WENT WRONG MAKE A SUPPORT THREAD AND CLOSE THIS APP"); + LogHelper.User("IF IT DID FINISH TYPE YES NOW"); + complete = Console.ReadLine(); + } + + // if user input "yes" kill patcher process, delete patcher.exe, extract aki zip + if (string.Equals(complete, "yes", StringComparison.OrdinalIgnoreCase)) + { + patcherProcess.EndProcess(); + Thread.Sleep(1000); + FileHelper.DeleteFile("file", Environment.CurrentDirectory + "/patcher.exe"); + ZipHelper.Decompress(akiRef, Environment.CurrentDirectory); + LogHelper.Info("AKI HAS BEEN EXTRACTED, RUN THE SERVER AND WAIT TILL YOU SEE HAPPY SERVER THEN LAUNCHER AND ENJOY!"); + LogHelper.User("PRESS ENTER TO CLOSE THE APP"); + Console.ReadKey(); + } + } + + private static bool PatcherCheck(string gamePath, out string patchRef) + { + FileVersionInfo version = FileVersionInfo.GetVersionInfo(Path.Join(gamePath + "/EscapeFromTarkov.exe")); + string versionCheck = StringHelper.Splitter(version.ProductVersion, '-', '.', 2); + LogHelper.Info($"GAME VERSION IS: {version.ProductVersion}"); + string patcherRef = FileHelper.FindFile(Environment.CurrentDirectory, versionCheck); + + if (patcherRef != null) + { + patchRef = patcherRef; + return true; + } + patchRef = null; + return false; + } + + private static bool AkiCheck(out string akiRef) + { + string aki = FileHelper.FindFile(Environment.CurrentDirectory, "2.3.1"); + + if (aki != null) + { + akiRef = aki; + return true; + } + akiRef = null; + return false; + } + } +} \ No newline at end of file diff --git a/Aki.Helper/FileHelper.cs b/Aki.Helper/FileHelper.cs new file mode 100644 index 0000000..8f37818 --- /dev/null +++ b/Aki.Helper/FileHelper.cs @@ -0,0 +1,101 @@ +using System; +using System.IO; + +namespace Installer.Aki.Helper +{ + public static class FileHelper + { + /// + /// CopyDirectory will use old path and copy to new path and + /// asks if inner files/folders should be included + /// + /// + public static void CopyDirectory(string oldDir, string newDir, bool recursive) + { + var dir = new DirectoryInfo(oldDir); + + if (!dir.Exists) + throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}"); + + DirectoryInfo[] dirs = dir.GetDirectories(); + + Directory.CreateDirectory(newDir); + + foreach (FileInfo file in dir.GetFiles()) + { + Console.WriteLine(file.FullName); + string targetFilePath = Path.Combine(newDir, file.Name); + file.CopyTo(targetFilePath, true); + } + + if (recursive) + { + foreach (DirectoryInfo subDir in dirs) + { + string newDestinationDir = Path.Combine(newDir, subDir.Name); + CopyDirectory(subDir.FullName, newDestinationDir, true); + } + } + } + + /// + /// DeleteFiles will use a type to look for, the path + /// and if all inner files/folders should be included + /// + /// + /// Types are "file" or "folder" as a string + /// + public static void DeleteFile(string type, string filePath, bool allFolders = false) + { + // type = "file" or "folder" + if (string.Equals(type, "file", StringComparison.OrdinalIgnoreCase)) + { + File.Delete(filePath); + } + + if (string.Equals(type, "folder", StringComparison.OrdinalIgnoreCase)) + { + Directory.Delete(filePath, allFolders); + } + } + + /// + /// finds file based on Path and File name + /// + /// + /// + /// String or null + public static string FindFile(string path, string name) + { + string[] filePaths = Directory.GetFiles(path); + foreach (string file in filePaths) + { + if (file.Contains(name)) + { + return file; + } + } + return null; + } + + /// + /// Finds folder with name supplied + /// + /// + /// + /// + public static bool FindFolder(string patchRef, out DirectoryInfo dir) + { + var patchInfo = new FileInfo(patchRef); + var patchName = patchInfo.Name.Replace(patchInfo.Extension, ""); + var path = new DirectoryInfo(Path.Join(Environment.CurrentDirectory, patchName)); + if (path.Exists) + { + dir = path; + return true; + } + dir = null; + return false; + } + } +} diff --git a/Aki.Helper/GameHelper.cs b/Aki.Helper/GameHelper.cs new file mode 100644 index 0000000..4cc3bc0 --- /dev/null +++ b/Aki.Helper/GameHelper.cs @@ -0,0 +1,23 @@ +using Microsoft.Win32; +using System.Runtime.InteropServices; +using System.IO; + +namespace Installer.Aki.Helper +{ + public static class GameHelper + { + private const string registryInstall = @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\EscapeFromTarkov"; + + public static string DetectOriginalGamePath() + { + // We can't detect the installed path on non-Windows + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return null; + + var uninstallStringValue = Registry.LocalMachine.OpenSubKey(registryInstall, false) + ?.GetValue("UninstallString"); + var info = (uninstallStringValue is string key) ? new FileInfo(key) : null; + return info?.DirectoryName; + } + } +} diff --git a/Aki.Helper/LogHelper.cs b/Aki.Helper/LogHelper.cs new file mode 100644 index 0000000..dd5d037 --- /dev/null +++ b/Aki.Helper/LogHelper.cs @@ -0,0 +1,55 @@ +using System; + +namespace Installer.Aki.Helper +{ + public static class LogHelper + { + /// + /// Outputs a string to console starting with [USER] with + /// a Green background and Black foreground + /// + public static void User(string text) + { + Console.BackgroundColor = ConsoleColor.Green; + Console.ForegroundColor = ConsoleColor.Black; + Console.WriteLine($"[USER]: {text}"); + Console.ResetColor(); + } + + /// + /// Outputs a string to console starting with [WARNING] with + /// a Yellow background and Black foreground + /// + public static void Warning(string text) + { + Console.BackgroundColor = ConsoleColor.Yellow; + Console.ForegroundColor = ConsoleColor.Black; + Console.WriteLine($"[WARNING]: {text}"); + Console.ResetColor(); + } + + /// + /// Outputs a string to console starting with [ERROR] with + /// a Red background and Black foreground + /// + public static void Error(string text) + { + Console.BackgroundColor = ConsoleColor.Red; + Console.ForegroundColor = ConsoleColor.Black; + Console.WriteLine($"[ERROR]: {text}"); + Console.ResetColor(); + } + + /// + /// Outputs a string to console starting with [INFO] with + /// a DarkGray background and White foreground + /// + public static void Info(string text) + { + Console.BackgroundColor = ConsoleColor.DarkGray; + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine($"[INFO]: {text}"); + Console.ResetColor(); + } + } +} diff --git a/Aki.Helper/ProcessHelper.cs b/Aki.Helper/ProcessHelper.cs new file mode 100644 index 0000000..b3d7db1 --- /dev/null +++ b/Aki.Helper/ProcessHelper.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.IO; +using System.Diagnostics; + +namespace Installer.Aki.Helper +{ + public class ProcessHelper + { + private Process _process; + + /// + /// Starts process with path and file name including include .exe, + /// sets working directory too + /// + public void StartProcess(string exeDir, string workingDir) + { + _process = new Process(); + _process.StartInfo.FileName = exeDir; + _process.StartInfo.WorkingDirectory = workingDir; + _process.Start(); + } + + /// + /// Kills the Process + /// + public void EndProcess() + { + _process.Kill(); + } + } +} diff --git a/Aki.Helper/StringHelper.cs b/Aki.Helper/StringHelper.cs new file mode 100644 index 0000000..476d7f0 --- /dev/null +++ b/Aki.Helper/StringHelper.cs @@ -0,0 +1,18 @@ +namespace Installer.Aki.Helper +{ + public static class StringHelper + { + /// + /// string to split, changes oldChar to newChar + /// + /// + /// + /// + /// + /// returns the string at a position using amount + public static string Splitter(string toSplit, char oldChar, char newChar, int amount) + { + return toSplit.Replace(oldChar, newChar).Split(newChar)[^amount]; + } + } +} diff --git a/Aki.Helper/ZipHelper.cs b/Aki.Helper/ZipHelper.cs new file mode 100644 index 0000000..f14c52c --- /dev/null +++ b/Aki.Helper/ZipHelper.cs @@ -0,0 +1,33 @@ +using SharpCompress.Common; +using SharpCompress.Readers; +using System; +using System.IO; + +namespace Installer.Aki.Helper +{ + public static class ZipHelper + { + /// + /// will extract Zips in LZMA compression format, using Zips path + /// to new path + /// + public static void Decompress(string zipPath, string extPath) + { + Stream stream = File.OpenRead(zipPath); + var reader = ReaderFactory.Open(stream); + + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + Console.WriteLine(reader.Entry.Key); + reader.WriteEntryToDirectory(extPath, new ExtractionOptions() + { + ExtractFullPath = true, + Overwrite = true + }); + } + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..bc3589f --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# SPTinstaller. +## EFT - SPT-AKI. - 2.3.1 + +### New implementation of an Installer for SPT-AKI. +- copies files from registry location to new location, +- extracts, runs and deletes patcher with minor user input, +- extracts Aki + +### plans: +- maybe download right version for EFT patcher and server +- maybe make a cool UI :OWO: + + diff --git a/SPT-AKI Installer.csproj b/SPT-AKI Installer.csproj new file mode 100644 index 0000000..b4e56e0 --- /dev/null +++ b/SPT-AKI Installer.csproj @@ -0,0 +1,24 @@ + + + + Exe + net6.0 + true + true + true + true + Aki.Asset\icon.ico + win-x64 + embedded + + + + + + + + + + + + diff --git a/SPT-AKI Installer.sln b/SPT-AKI Installer.sln new file mode 100644 index 0000000..577839a --- /dev/null +++ b/SPT-AKI Installer.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32407.343 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SPT-AKI Installer", "SPT-AKI Installer.csproj", "{7B07749A-3BE8-41B5-9B98-9F41C83FA15B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7B07749A-3BE8-41B5-9B98-9F41C83FA15B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B07749A-3BE8-41B5-9B98-9F41C83FA15B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B07749A-3BE8-41B5-9B98-9F41C83FA15B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B07749A-3BE8-41B5-9B98-9F41C83FA15B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6F8EE63B-3DC5-4168-A560-9B39F7785D84} + EndGlobalSection +EndGlobal