diff --git a/README.md b/README.md index 08b5bb2c..c68c2783 100644 --- a/README.md +++ b/README.md @@ -22,21 +22,6 @@ Wabbajack is an automated ModList installer that can recreate contents of a fold | Skyrim Special Edition | Steam | MO2 | | | Fallout 4 | Steam | MO2 | | | Skyrim VR | Steam | MO2 | | -| Darkest Dungeon | Steam, GOG| Vortex | | -| Divinity Original Sin 2 | Steam, GOG| Vortex | Normal and Definitive Edition | -| Starbound | Steam, GOG| Vortex | | -| Stardew Valley | Steam, GOG| Vortex | | -| SW: KotOR | Steam, GOG| Vortex | | -| SW: KotOR 2 | Steam, GOG| Vortex | | -| The Witcher | Steam, GOG| Vortex | Enhanced Edition | -| The Witcher 2 | Steam, GOG| Vortex | | -| The Witcher 3 | Steam, GOG| Vortex | Normal and GotY Edition | - -### Note about Vortex Support - -As you can probably guess from the table above: You will not be able to create ModLists from a Vortex installation for TES/Fallout games. The Vortex Support we're offering is designed for smaller games like Darkest Dungeon where you simply install mods, rearrange load order and be done. You do not need external tools like xEdit, DynDOLOD, CAO, FNIS and what not to mod these smaller games. - -It is also important to note that Vortex Support is still in **early beta** meaning that stuff can go wrong, very fast. If you encounter such problems be sure to join our [Discord](https://discord.gg/zgbrkmA) and message `erri120#2285` about the error. ## Installing a ModList @@ -44,8 +29,6 @@ Every ModList comes with its own set of instructions which you **should** read b A ModList comes as a `.wabbajack` file. You might have a `.zip`, `.7z` or `.rar` file which contains the ModList so extract the archive using [7zip](https://www.7-zip.org/) before starting Wabbajack. Once extracted, start Wabbajack and click on the _Install a ModList from Disk_ button and select the extracted `.wabbajack` file. -Wabbajack will know if this ModList was compiled from an MO2 profile or a Vortex installation. For the former it downloads MO2 for you but for the latter you need an existing Vortex installation. - On the installation screen, configure the installation/staging and downloads folder before clicking the begin button. Once everything is correctly setup, the button will be clickable and you can proceed with the installation. The installation can take everything from a few minutes to hours depending on the size of the ModList, your Internet speed and your hardware so just be patient and wait for _Installation complete! You may exit the program._ to appear in the log. @@ -100,18 +83,6 @@ When everything is correctly set up, click the begin button and wait for Wabbaja Wabbajack is finished when you see _Done Building ModList_ in the log. At that point you can close Wabbajack and the `.wabbajack` file will be located in the same folder as `Wabbajack.exe`. -### Creating a ModList from an Vortex installation - -**THIS IS STILL IN BETA** for more info see [this](#note-about-vortex-support) section. - -Before you start compiling a ModList, make sure that the Vortex download folder for your game of choice only contains mods downloaded from the Nexus. The `VortexCompiler` will create an MD5 hash for the archive and search the Nexus using said hash. - -Open Wabbajack and click on _Create a ModList_. Select Vortex and your game of choice. The _Staging_ and _Downloads_ folder will be filled automatically if they are at the default location. If you have changed these folders, be sure to change the paths in Wabbajack. - -When everything is correctly set up, click the begin button and wait for Wabbajack to finish. Depeding on your hardware, size of your Vortex staging folder and game of choice, this can take up anything from a few minutes to hours. Do note that whenever Wabbajack has an error you can restart the compilation and Wabbajack will resume at the exact position. - -Wabbajack is finished when you see _Done Building ModList_ in the log. At that point you can close Wabbajack and the `.wabbajack` file will be located in the same folder as `Wabbajack.exe`. - ## FAQ **How can I get Wabbajack to handle mods from `X`?** diff --git a/Wabbajack.Common/Enums/ModManager.cs b/Wabbajack.Common/Enums/ModManager.cs index 05ccd1fb..e8001c5e 100644 --- a/Wabbajack.Common/Enums/ModManager.cs +++ b/Wabbajack.Common/Enums/ModManager.cs @@ -3,6 +3,5 @@ public enum ModManager { MO2, - Vortex } } diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index 752419b0..c1e74a9d 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -386,7 +386,6 @@ namespace Wabbajack.Common { Game.DarkestDungeon, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.DarkestDungeon, NexusName = "darkestdungeon", NexusGameId = 804, @@ -401,7 +400,6 @@ namespace Wabbajack.Common { Game.DivinityOriginalSin2DE, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.DivinityOriginalSin2DE, NexusName = "divinityoriginalsin2definitiveedition", NexusGameId = 2569, @@ -420,7 +418,6 @@ namespace Wabbajack.Common { Game.DivinityOriginalSin2, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.DivinityOriginalSin2, NexusName = "divinityoriginalsin2", NexusGameId = 1661, @@ -439,7 +436,6 @@ namespace Wabbajack.Common { Game.Starbound, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.Starbound, NexusName = "starbound", NexusGameId = 242, @@ -454,7 +450,6 @@ namespace Wabbajack.Common { Game.SWKOTOR, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.SWKOTOR, NexusName = "kotor", NexusGameId = 234, @@ -469,7 +464,6 @@ namespace Wabbajack.Common { Game.SWKOTOR2, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.SWKOTOR2, NexusName = "kotor2", NexusGameId = 198, @@ -484,7 +478,6 @@ namespace Wabbajack.Common { Game.Witcher, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.Witcher, NexusName = "witcher", NexusGameId = 150, @@ -499,7 +492,6 @@ namespace Wabbajack.Common { Game.Witcher2, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.Witcher2, NexusName = "witcher2", NexusGameId = 153, @@ -515,7 +507,6 @@ namespace Wabbajack.Common { Game.Witcher3, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.Witcher3, NexusName = "witcher3", NexusGameId = 952, @@ -530,7 +521,6 @@ namespace Wabbajack.Common { Game.StardewValley, new GameMetaData { - SupportedModManager = ModManager.Vortex, Game = Game.StardewValley, NexusName = "stardewvalley", NexusGameId = 1303, diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledVortexMods.cs b/Wabbajack.Lib/CompilationSteps/IgnoreDisabledVortexMods.cs deleted file mode 100644 index 4694905a..00000000 --- a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledVortexMods.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Threading.Tasks; -using Wabbajack.Common; - -namespace Wabbajack.Lib.CompilationSteps -{ - public class IgnoreDisabledVortexMods : ACompilationStep - { - private readonly VortexCompiler _vortexCompiler; - - public IgnoreDisabledVortexMods(ACompiler compiler) : base(compiler) - { - _vortexCompiler = (VortexCompiler) compiler; - } - - public override async ValueTask Run(RawSourceFile source) - { - var b = false; - _vortexCompiler.ActiveArchives.Do(a => - { - if (((string)source.Path).Contains(a)) b = true; - }); - if (b) return null; - var r = source.EvolveTo(); - r.Reason = "Disabled Archive"; - return r; - } - - public override IState GetState() - { - return new State(); - } - - public class State : IState - { - public ICompilationStep CreateStep(ACompiler compiler) - { - return new IgnoreDisabledVortexMods(compiler); - } - } - } -} diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreVortex.cs b/Wabbajack.Lib/CompilationSteps/IgnoreVortex.cs deleted file mode 100644 index b3282001..00000000 --- a/Wabbajack.Lib/CompilationSteps/IgnoreVortex.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.IO; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace Wabbajack.Lib.CompilationSteps -{ - public class IgnoreVortex : ACompilationStep - { - private readonly VortexCompiler _vortex; - - public IgnoreVortex(ACompiler compiler) : base(compiler) - { - _vortex = (VortexCompiler) compiler; - } - - public override async ValueTask Run(RawSourceFile source) - { - if (source.AbsolutePath.Parent != _vortex.DownloadsFolder) return null; - var result = source.EvolveTo(); - result.Reason = "Ignored because it is a Vortex file"; - return result; - - } - - public override IState GetState() - { - return new State(); - } - - [JsonObject("IgnoreVortex")] - public class State : IState - { - public ICompilationStep CreateStep(ACompiler compiler) - { - return new IgnoreVortex(compiler); - } - } - } -} diff --git a/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs b/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs deleted file mode 100644 index 19a386dc..00000000 --- a/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Wabbajack.Common; - -namespace Wabbajack.Lib.CompilationSteps -{ - public class IncludeVortexDeployment : ACompilationStep - { - public IncludeVortexDeployment(ACompiler compiler) : base(compiler) - { - } - - public override async ValueTask Run(RawSourceFile source) - { - // * TODO I don't know what this does - /* - var l = new List {"vortex.deployment.msgpack", "vortex.deployment.json"}; - if (!l.Any(a => ((string)source.Path).Contains(a))) return null; - var inline = source.EvolveTo(); - inline.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath)); - if (!((string)source.Path).Contains("vortex.deployment.json")) - return inline; - - var path = source.Path; - if (!path.StartsWith(Consts.GameFolderFilesDir)) - return inline; - */ - //path = ((string)path).Substring(Consts.GameFolderFilesDir.Length + 1); - //path = $"{Consts.ManualGameFilesDir}\\{path}"; - //inline.To = path; - - return null; - } - - public override IState GetState() - { - return new State(); - } - - public class State : IState - { - public ICompilationStep CreateStep(ACompiler compiler) - { - return new IncludeVortexDeployment(compiler); - } - } - } -} diff --git a/Wabbajack.Lib/VortexCompiler.cs b/Wabbajack.Lib/VortexCompiler.cs deleted file mode 100644 index 4ad94116..00000000 --- a/Wabbajack.Lib/VortexCompiler.cs +++ /dev/null @@ -1,555 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using System.Threading; -using Newtonsoft.Json; -using Wabbajack.Common; -using Wabbajack.Common.IO; -using Wabbajack.Common.StoreHandlers; -using Wabbajack.Lib.CompilationSteps; -using Wabbajack.Lib.NexusApi; -using Wabbajack.Lib.Validation; -using File = Alphaleonis.Win32.Filesystem.File; -using Game = Wabbajack.Common.Game; - -namespace Wabbajack.Lib -{ - public class VortexCompiler : ACompiler - { - /* vortex creates a vortex.deployment.json file that contains information - about all deployed files, parsing that file, we can get a list of all 'active' - archives so we don't force the user to install all archives found in the downloads folder. - Similar to how IgnoreDisabledMods for MO2 works - */ - public VortexDeployment VortexDeployment; - public List ActiveArchives; - - public Game Game { get; } - public string GameName { get; } - - public AbsolutePath VortexFolder { get; set; } - public AbsolutePath StagingFolder { get; set; } - public AbsolutePath DownloadsFolder { get; set; } - - public override ModManager ModManager => ModManager.Vortex; - public override AbsolutePath GamePath { get; } - public override AbsolutePath ModListOutputFolder => ((RelativePath)"output_folder").RelativeToEntryPoint(); - public override AbsolutePath ModListOutputFile { get; } - - public const string StagingMarkerName = "__vortex_staging_folder"; - public const string DownloadMarkerName = "__vortex_downloads_folder"; - - //private bool _isSteamGame = true; - private SteamGame _steamGame; - private bool _hasSteamWorkshopItems; - - public override AbsolutePath VFSCacheName => Consts.LocalAppDataPath.Combine($"vfs_compile_cache-{((string)StagingFolder)?.StringSha256Hex() ?? "Unknown"}.bin"); - - public VortexCompiler(Game game, AbsolutePath gamePath, AbsolutePath vortexFolder, AbsolutePath downloadsFolder, AbsolutePath stagingFolder, AbsolutePath outputFile) - { - Game = game; - - GamePath = gamePath; - GameName = game.MetaData().NexusName; - VortexFolder = vortexFolder; - DownloadsFolder = downloadsFolder; - StagingFolder = stagingFolder; - ModListOutputFile = outputFile; - - if (string.IsNullOrEmpty(ModListName)) - { - ModListName = $"Vortex ModList for {Game.ToString()}"; - ModListOutputFile = ((RelativePath)ModListName).RelativeToEntryPoint().WithExtension(Consts.ModListExtension); - } - - GameName = Game.MetaData().NexusName; - - ActiveArchives = new List(); - - // there can be max one game after filtering - /* - StoreHandler.Instance.StoreGames.Where(g => g.Game == game && g.Type == StoreType.STEAM).Do(g => - { - _isSteamGame = true; - _steamGame = (SteamGame)g; - _hasSteamWorkshopItems = _steamGame.WorkshopItems.Count > 0; - }); - */ - } - - protected override async Task _Begin(CancellationToken cancel) - { - if (cancel.IsCancellationRequested) return false; - - Info($"Starting Vortex compilation for {GameName} at {GamePath} with staging folder at {StagingFolder} and downloads folder at {DownloadsFolder}."); - - ConfigureProcessor(12, ConstructDynamicNumThreads(await RecommendQueueSize())); - UpdateTracker.Reset(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Parsing deployment file"); - ParseDeploymentFile(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Creating metas for archives"); - await CreateMetaFiles(); - - Utils.Log($"VFS File Location: {VFSCacheName}"); - - if (cancel.IsCancellationRequested) return false; - await VFS.IntegrateFromFile(VFSCacheName); - - var roots = new List {StagingFolder, GamePath, DownloadsFolder}; - AddExternalFolder(ref roots); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Indexing folders"); - await VFS.AddRoots(roots); - await VFS.WriteToFile(VFSCacheName); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Cleaning output folder"); - await ModListOutputFolder.DeleteDirectory(); - ModListOutputFolder.CreateDirectory(); - - UpdateTracker.NextStep("Finding Install Files"); - /* TODO - var vortexStagingFiles = Directory.EnumerateFiles(StagingFolder, "*", SearchOption.AllDirectories) - .Where(p => p.FileExists() && p != StagingMarkerName && !p.Contains(Consts.ManualGameFilesDir)) - .Select(p => new RawSourceFile(VFS.Index.ByRootPath[p], p.RelativeTo(StagingFolder))); - - var vortexDownloads = Directory.EnumerateFiles(DownloadsFolder, "*", SearchOption.AllDirectories) - .Where(p => p.FileExists() && p != DownloadMarkerName) - .Select(p => new RawSourceFile(VFS.Index.ByRootPath[p], p.RelativeTo(DownloadsFolder))); - - var gameFiles = Directory.EnumerateFiles(GamePath, "*", SearchOption.AllDirectories) - .Where(p => p.FileExists()) - .Select(p => new RawSourceFile(VFS.Index.ByRootPath[p], Path.Combine(Consts.GameFolderFilesDir, p.RelativeTo(GamePath)))); - - Info("Indexing Archives"); - IndexedArchives = Directory.EnumerateFiles(DownloadsFolder) - .Where(f => File.Exists(f + Consts.MetaFileExtension)) - .Select(f => new IndexedArchive - { - File = VFS.Index.ByRootPath[f], - Name = Path.GetFileName(f), - IniData = (f + Consts.MetaFileExtension).LoadIniFile(), - Meta = File.ReadAllText(f + Consts.MetaFileExtension) - }) - .ToList(); - - Info("Indexing Files"); - IndexedFiles = IndexedArchives.SelectMany(f => f.File.ThisAndAllChildren) - .OrderBy(f => f.NestingFactor) - .GroupBy(f => f.Hash) - .ToDictionary(f => f.Key, f => f.AsEnumerable()); - - AllFiles = vortexStagingFiles.Concat(vortexDownloads) - .Concat(gameFiles) - .DistinctBy(f => f.Path) - .ToList(); - - Info($"Found {AllFiles.Count} files to build into mod list"); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Verifying destinations"); - var duplicates = AllFiles.GroupBy(f => f.Path) - .Where(fs => fs.Count() > 1) - .Select(fs => - { - Utils.Log($"Duplicate files installed to {fs.Key} from : {string.Join(", ", fs.Select(f => f.AbsolutePath))}"); - return fs; - }).ToList(); - - if (duplicates.Count > 0) - { - Error($"Found {duplicates.Count} duplicates, exiting"); - } - - for (var i = 0; i < AllFiles.Count; i++) - { - var f = AllFiles[i]; - if (!f.Path.StartsWith(Consts.GameFolderFilesDir) || !IndexedFiles.ContainsKey(f.Hash)) - continue; - - if (!IndexedFiles.TryGetValue(f.Hash, out var value)) - continue; - - var element = value.ElementAt(0); - - if (!f.Path.Contains(element.Name)) - continue; - - IndexedArchive targetArchive = null; - IndexedArchives.Where(a => a.File.ThisAndAllChildren.Contains(element)).Do(a => targetArchive = a); - - if (targetArchive == null) - continue; - - if(targetArchive.IniData?.General?.tag == null || targetArchive.IniData?.General?.tag != Consts.WABBAJACK_VORTEX_MANUAL) - continue; - - #if DEBUG - Utils.Log($"Double hash for: {f.AbsolutePath}"); - #endif - - var replace = f; - var name = replace.File.Name; - var archiveName = targetArchive.Name; - var elementPath = element.FullPath.Substring(element.FullPath.LastIndexOf('|')+1); - var gameToFile = name.Substring(GamePath.Length + 1).Replace(elementPath, ""); - if (gameToFile.EndsWith("\\")) - gameToFile = gameToFile.Substring(0, gameToFile.Length - 1); - //replace.Path = replace.Path.Replace(Consts.GameFolderFilesDir, Consts.ManualGameFilesDir); - replace.Path = Path.Combine(Consts.ManualGameFilesDir, archiveName, gameToFile, elementPath); - //replace.Path = Path.Combine(Consts.ManualGameFilesDir, element.FullPath.Substring(DownloadsFolder.Length + 1).Replace('|', '\\')); - AllFiles.RemoveAt(i); - AllFiles.Insert(i, replace); - //AllFiles.Replace(f, replace); - } - - var stack = MakeStack(); - - Info("Running Compilation Stack"); - var results = await AllFiles.PMap(Queue, f => RunStack(stack.Where(s => s != null), f)); - - var noMatch = results.OfType().ToList(); - PrintNoMatches(noMatch); - if (CheckForNoMatchExit(noMatch)) return false; - - InstallDirectives = results.Where(i => !(i is IgnoredDirectly)).ToList(); - - Info("Getting Nexus api_key, please click authorize if a browser window appears"); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Gathering Archives"); - await GatherArchives(); - - ModList = new ModList - { - Name = ModListName ?? "", - Author = ModListAuthor ?? "", - Description = ModListDescription ?? "", - Readme = ModListReadme ?? "", - Image = ModListImage ?? "", - Website = ModListWebsite != null ? new Uri(ModListWebsite) : null, - Archives = SelectedArchives.ToList(), - ModManager = ModManager.Vortex, - Directives = InstallDirectives, - GameType = Game - }; - - UpdateTracker.NextStep("Running Validation"); - await ValidateModlist.RunValidation(ModList); - - UpdateTracker.NextStep("Generating Report"); - GenerateManifest(); - - UpdateTracker.NextStep("Exporting ModList"); - ExportModList(); - - ResetMembers(); - - UpdateTracker.NextStep("Done Building ModList"); - */ - - return true; - } - - /// - /// Clear references to lists that hold a lot of data. - /// - private void ResetMembers() - { - AllFiles = null; - InstallDirectives = null; - SelectedArchives = null; - } - - private void AddExternalFolder(ref List roots) - { - var currentGame = Game.MetaData(); - if (currentGame.AdditionalFolders == null || currentGame.AdditionalFolders.Count == 0) return; - foreach (var path in currentGame.AdditionalFolders.Select(f => f.Replace("%documents%", KnownFolders.Documents.Path))) - { - if (!Directory.Exists(path)) return; - roots.Add((AbsolutePath)path); - } - } - - private void ParseDeploymentFile() - { - /* TODO - Info("Searching for vortex.deployment.json..."); - - var deploymentFile = ""; - Directory.EnumerateFiles(GamePath, "vortex.deployment.json", SearchOption.AllDirectories) - .Where(File.Exists) - .Do(f => deploymentFile = f); - var currentGame = Game.MetaData(); - if (currentGame.AdditionalFolders != null && currentGame.AdditionalFolders.Count != 0) - currentGame.AdditionalFolders.Do(f => Directory.EnumerateFiles(f, "vortex.deployment.json", SearchOption.AllDirectories) - .Where(File.Exists) - .Do(d => deploymentFile = d)); - - if (string.IsNullOrEmpty(deploymentFile)) - { - Error("vortex.deployment.json not found!"); - return; - } - Info($"vortex.deployment.json found at {deploymentFile}"); - - Info("Parsing vortex.deployment.json..."); - try - { - VortexDeployment = deploymentFile.FromJSON(); - } - catch (JsonSerializationException e) - { - Utils.Error(e, "Failed to parse vortex.deployment.json!"); - } - - VortexDeployment.files.Do(f => - { - var archive = f.source; - if (ActiveArchives.Contains(archive)) - return; - - Utils.Log($"Adding archive {archive} to ActiveArchives"); - ActiveArchives.Add(archive); - }); - */ - } - - private async Task CreateMetaFiles() - { - /* - Utils.Log("Getting Nexus API key, please click authorize if a browser window appears"); - var nexusClient = await NexusApiClient.Get(); - - var archives = Directory.EnumerateFiles(DownloadsFolder, "*", SearchOption.TopDirectoryOnly).Where(f => - File.Exists(f) && Path.GetExtension(f) != Consts.MetaFileExtension && Path.GetExtension(f) != Consts.HashFileExtension && - !File.Exists($"{f}.meta") && ActiveArchives.Contains(Path.GetFileNameWithoutExtension(f))); - - await archives.PMap(Queue, async f => - { - Info($"Creating meta file for {Path.GetFileName(f)}"); - var metaString = "[General]\n" + - "repository=Nexus\n" + - $"gameName={GameName}\n"; - string hash; - using (var md5 = MD5.Create()) - using (var stream = File.OpenRead(f)) - { - Utils.Log($"Calculating hash for {Path.GetFileName(f)}"); - var cH = md5.ComputeHash(stream); - hash = BitConverter.ToString(cH).Replace("-", "").ToLowerInvariant(); - Utils.Log($"Hash is {hash}"); - } - - var md5Response = await nexusClient.GetModInfoFromMD5(Game, hash); - if (md5Response.Count >= 1) - { - var modInfo = md5Response[0].mod; - metaString += $"modID={modInfo.mod_id}\n" + - $"modName={modInfo.name}\n" + - $"fileID={md5Response[0].file_details.file_id}\n" + - $"version={md5Response[0].file_details.version}\n" + - $"hash={hash}\n"; - File.WriteAllText(f + Consts.MetaFileExtension, metaString, Encoding.UTF8); - } - else - { - Error("Error while getting information from NexusMods via MD5 hash!"); - } - }); - - var otherFiles = Directory.EnumerateFiles(DownloadsFolder, "*", SearchOption.TopDirectoryOnly).Where(f => - Path.GetExtension(f) == Consts.MetaFileExtension && !ActiveArchives.Contains(Path.GetFileNameWithoutExtension(f))); - - await otherFiles.PMap(Queue, async f => - { - Info($"File {f} is not in ActiveArchives"); - var lines = File.ReadAllLines(f); - if (lines.Length == 0 || !lines.Any(line => lines.Contains("directURL="))) - { - if (lines.Length == 0) - return; - - lines.Do(line => - { - var tag = ""; - if (line.Contains("tag=")) - tag = line.Substring("tag=".Length); - - if (tag != Consts.WABBAJACK_VORTEX_MANUAL) - return; - - Info($"File {f} contains the {Consts.WABBAJACK_VORTEX_MANUAL} tag, adding to ActiveArchives"); - ActiveArchives.Add(Path.GetFileNameWithoutExtension(f)); - }); - } - else - { - Info($"File {f} appears to not be from the Nexus, adding to ActiveArchives"); - ActiveArchives.Add(Path.GetFileNameWithoutExtension(f)); - } - }); - - Info("Checking for Steam Workshop Items..."); - if (!_isSteamGame || _steamGame == null || !_hasSteamWorkshopItems) - return; - - _steamGame.WorkshopItems.Do(item => - { - var filePath = Path.Combine(DownloadsFolder, $"steamWorkshopItem_{item.ItemID}.meta"); - if (File.Exists(filePath)) - { - Utils.Log($"File {filePath} already exists, skipping"); - return; - } - - Utils.Log($"Creating meta file for {item.ItemID}"); - var metaString = "[General]\n" + - "repository=Steam\n" + - $"gameName={GameName}\n" + - $"steamID={_steamGame.ID}\n" + - $"itemID={item.ItemID}\n" + - $"itemSize={item.Size}\n"; - try - { - File.WriteAllText(filePath, metaString); - } - catch (Exception e) - { - Utils.Error(e, $"Exception while writing to disk at {filePath}"); - } - }); - */ - } - - public override IEnumerable GetStack() - { - /* - var s = Consts.TestMode ? DownloadsFolder : VortexFolder; - var userConfig = Path.Combine(s, "compilation_stack.yml"); - if (File.Exists(userConfig)) - return Serialization.Deserialize(File.ReadAllText(userConfig), this); - - var stack = MakeStack(); - - var compilationSteps = stack.ToList(); - File.WriteAllText(Path.Combine(s, "_current_compilation_stack.yml"), - Serialization.Serialize(compilationSteps)); - - return compilationSteps; - */ - return null; - } - - public override IEnumerable MakeStack() - { - Info("Generating compilation stack"); - return new List - { - new IncludePropertyFiles(this), - new IncludeVortexDeployment(this), - - new IncludeSteamWorkshopItems(this, _steamGame), - _hasSteamWorkshopItems ? new IncludeRegex(this, "^steamWorkshopItem_\\d*\\.meta$") : null, - - new IgnoreDisabledVortexMods(this), - new IgnoreVortex(this), - new IgnoreRegex(this, $"^*{StagingMarkerName}$"), - - Game == Game.DarkestDungeon ? new IncludeRegex(this, "project\\.xml$") : null, - - /* - new IgnoreStartsWith(this, StagingFolder), - new IgnoreEndsWith(this, StagingFolder), - */ - - new IgnoreGameFiles(this), - - new DirectMatch(this), - // new IncludeTaggedMods(this, Consts.WABBAJACK_INCLUDE), disabled until further refactoring - - new IgnoreGameFiles(this), - - new IgnoreWabbajackInstallCruft(this), - - new DropAll(this) - }; - } - - public static string TypicalVortexFolder() - { - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Vortex"); - } - - public static string RetrieveDownloadLocation(Game game, string vortexFolderPath = null) - { - vortexFolderPath = vortexFolderPath ?? TypicalVortexFolder(); - return Path.Combine(vortexFolderPath, "downloads", game.MetaData().NexusName); - } - - public static string RetrieveStagingLocation(Game game, string vortexFolderPath = null) - { - /* - vortexFolderPath = vortexFolderPath ?? TypicalVortexFolder(); - var gameName = game.MetaData().NexusName; - return Path.Combine(vortexFolderPath, gameName, Consts.MO2ModFolderName); - */ - return null; - } - - - public static IErrorResponse IsValidBaseDownloadsFolder(string path) - { - if (!Directory.Exists(path)) return ErrorResponse.Fail($"Path does not exist: {path}"); - if (Directory.EnumerateFiles(path, DownloadMarkerName, SearchOption.TopDirectoryOnly).Any()) return ErrorResponse.Success; - return ErrorResponse.Fail($"Folder must contain {DownloadMarkerName} file"); - } - - public static IErrorResponse IsValidDownloadsFolder(string path) - { - return IsValidBaseDownloadsFolder(Path.GetDirectoryName(path)); - } - - public static IErrorResponse IsValidBaseStagingFolder(string path) - { - if (!Directory.Exists(path)) return ErrorResponse.Fail($"Path does not exist: {path}"); - if (Directory.EnumerateFiles(path, StagingMarkerName, SearchOption.TopDirectoryOnly).Any()) return ErrorResponse.Success; - return ErrorResponse.Fail($"Folder must contain {StagingMarkerName} file"); - } - - public static IErrorResponse IsValidStagingFolder(string path) - { - return IsValidBaseStagingFolder(Path.GetDirectoryName(path)); - } - - public static bool IsActiveVortexGame(Game g) - { - return g.MetaData().SupportedModManager == ModManager.Vortex && !GameRegistry.Games[g].Disabled; - } - } - - public class VortexDeployment - { - public string instance; - public int version; - public string deploymentMethod; - public List files; - } - - public class VortexFile - { - public string relPath; - public string source; - public string target; - } -} diff --git a/Wabbajack.Lib/VortexInstaller.cs b/Wabbajack.Lib/VortexInstaller.cs deleted file mode 100644 index 7876097d..00000000 --- a/Wabbajack.Lib/VortexInstaller.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using System.Threading; -using System.Windows; -using Wabbajack.Common; -using Wabbajack.Common.StoreHandlers; -using Directory = Alphaleonis.Win32.Filesystem.Directory; -using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo; -using File = Alphaleonis.Win32.Filesystem.File; -using Path = Alphaleonis.Win32.Filesystem.Path; -#nullable disable - -namespace Wabbajack.Lib -{ - public class VortexInstaller : AInstaller - { - public GameMetaData GameInfo { get; internal set; } - - public override ModManager ModManager => ModManager.Vortex; - - public VortexInstaller(AbsolutePath archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters) - : base( - archive: archive, - modList: modList, - outputFolder: outputFolder, - downloadFolder: downloadFolder, - parameters: parameters, - steps: 10) - { - #if DEBUG - // TODO: only for testing - IgnoreMissingFiles = true; - #endif - - GameInfo = ModList.GameType.MetaData(); - } - - protected override async Task _Begin(CancellationToken cancel) - { - if (cancel.IsCancellationRequested) return false; - var metric = Metrics.Send(Metrics.BeginInstall, ModList.Name); - var result = await Utils.Log(new YesNoIntervention( - "Vortex Support is still experimental and may produce unexpected results. " + - "If anything fails please go to the special Vortex support channels on the Wabbajack Discord and contact @erri120#2285 " + - "for support.", "Continue with experimental feature?")).Task; - if (result == ConfirmationIntervention.Choice.Abort) - { - Utils.Log("Exiting at request of user"); - return false; - } - - if (cancel.IsCancellationRequested) return false; - Queue.SetActiveThreadsObservable(ConstructDynamicNumThreads(await RecommendQueueSize())); - DownloadFolder.CreateDirectory(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Hashing Archives"); - await HashArchives(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Downloading Missing Archives"); - await DownloadArchives(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Hashing Remaining Archives"); - await HashArchives(); - - if (cancel.IsCancellationRequested) return false; - var missing = ModList.Archives.Where(a => !HashedArchives.ContainsKey(a.Hash)).ToList(); - if (missing.Count > 0) - { - foreach (var a in missing) - Info($"Unable to download {a.Name}"); - if (IgnoreMissingFiles) - Info("Missing some archives, but continuing anyways at the request of the user"); - else - Error("Cannot continue, was unable to download one or more archives"); - } - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Priming VFS"); - await PrimeVFS(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Building Folder Structure"); - BuildFolderStructure(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Installing Archives"); - await InstallArchives(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Installing Included files"); - await InstallIncludedFiles(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Installing Manual files"); - await InstallManualGameFiles(); - - if (cancel.IsCancellationRequested) return false; - UpdateTracker.NextStep("Installing SteamWorkshopItems"); - await InstallSteamWorkshopItems(); - - //InstallIncludedDownloadMetas(); - var metric2 = Metrics.Send(Metrics.FinishInstall, ModList.Name); - UpdateTracker.NextStep("Installation complete! You may exit the program."); - return true; - } - - private async Task InstallManualGameFiles() - { - if (!ModList.Directives.Any(d => d.To.StartsWith(Consts.ManualGameFilesDir))) - return; - - var result = await Utils.Log(new YesNoIntervention("Some mods from this ModList must be installed directly into " + - "the game folder. Do you want to do this manually or do you want Wabbajack " + - "to do this for you?", "Move mods into game folder?")).Task; - - if (result != ConfirmationIntervention.Choice.Continue) - return; - - var manualFilesDir = OutputFolder.Combine(Consts.ManualGameFilesDir); - - var gameFolder = GameInfo.TryGetGameLocation(); - - Info($"Copying files from {manualFilesDir} " + - $"to the game folder at {gameFolder}"); - - if (!manualFilesDir.Exists) - { - Info($"{manualFilesDir} does not exist!"); - return; - } - - /* TODO FIX THIS - await manualFilesDir.EnumerateFiles().PMap(Queue, dir => - { - dirInfo.GetDirectories("*", SearchOption.AllDirectories).Do(d => - { - var destPath = d.FullName.Replace(manualFilesDir, gameFolder); - Status($"Creating directory {destPath}"); - Directory.CreateDirectory(destPath); - }); - - dirInfo.GetFiles("*", SearchOption.AllDirectories).Do(f => - { - var destPath = f.FullName.Replace(manualFilesDir, gameFolder); - Status($"Copying file {f.FullName} to {destPath}"); - try - { - File.Copy(f.FullName, destPath); - } - catch (Exception) - { - Info($"Could not copy file {f.FullName} to {destPath}. The file may already exist, skipping..."); - } - }); - }); - - */ - } - - private async Task InstallSteamWorkshopItems() - { - //var currentLib = ""; - SteamGame currentSteamGame = null; - StoreHandler.Instance.SteamHandler.Games.Where(g => g.Game == GameInfo.Game).Do(s => currentSteamGame = (SteamGame)s); - /*SteamHandler.Instance.InstallFolders.Where(f => f.Contains(currentSteamGame.InstallDir)).Do(s => currentLib = s); - - var downloadFolder = Path.Combine(currentLib, "workshop", "downloads", currentSteamGame.AppId.ToString()); - var contentFolder = Path.Combine(currentLib, "workshop", "content", currentSteamGame.AppId.ToString()); - */ - if (!ModList.Directives.Any(s => s is SteamMeta)) - return; - - var result = await Utils.Log(new YesNoIntervention( - "The ModList you are installing requires Steam Workshop items to exist. " + - "You can check the Workshop Items in the manifest of this ModList. Wabbajack can start Steam for you " + - "and download the Items automatically. Do you want to proceed with this step?", - "Download Steam Workshop Items?")).Task; - - if (result != ConfirmationIntervention.Choice.Continue) - return; - - await ModList.Directives.OfType() - .PMap(Queue, async item => - { - Status("Extracting Steam meta file to temp folder"); - var path = DownloadFolder.Combine($"steamWorkshopItem_{item.ItemID}.meta"); - if (!path.Exists) - await path.WriteAllBytesAsync(await LoadBytesFromPath(item.SourceDataID)); - - Status("Downloading Steam Workshop Item through steam cmd"); - - var p = new Process - { - StartInfo = new ProcessStartInfo - { - FileName = Path.Combine(StoreHandler.Instance.SteamHandler.SteamPath, "steam.exe"), - CreateNoWindow = true, - Arguments = $"console +workshop_download_item {currentSteamGame.ID} {currentSteamGame.ID}" - } - }; - - p.Start(); - }); - } - - private async Task InstallIncludedFiles() - { - Info("Writing inline files"); - await ModList.Directives.OfType() - .PMap(Queue,async directive => - { - if (directive.To.Extension == Consts.MetaFileExtension) - return; - - Info($"Writing included file {directive.To}"); - var outPath = OutputFolder.Combine(directive.To); - outPath.Delete(); - await outPath.WriteAllBytesAsync(await LoadBytesFromPath(directive.SourceDataID)); - }); - } - } -} diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index d42dbf40..b98c4bec 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -96,12 +96,6 @@ PreserveNewest - - - - - - diff --git a/Wabbajack.Test/AVortexCompilerTest.cs b/Wabbajack.Test/AVortexCompilerTest.cs deleted file mode 100644 index 3de5b113..00000000 --- a/Wabbajack.Test/AVortexCompilerTest.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Wabbajack.Common; -using Wabbajack.Lib; - -namespace Wabbajack.Test -{ - public abstract class AVortexCompilerTest - { - public TestContext TestContext { get; set; } - protected TestUtils utils { get; set; } - - - [TestInitialize] - public void TestInitialize() - { - Consts.TestMode = true; - - utils = new TestUtils - { - Game = Game.DarkestDungeon - }; - - Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f.ShortDescription)); - } - - [TestCleanup] - public void TestCleanup() - { - utils.Dispose(); - } - - protected async Task ConfigureAndRunCompiler() - { - var vortexCompiler = MakeCompiler(); - vortexCompiler.DownloadsFolder = utils.DownloadsFolder; - vortexCompiler.StagingFolder = utils.InstallFolder; - Directory.CreateDirectory(utils.InstallFolder); - Assert.IsTrue(await vortexCompiler.Begin()); - return vortexCompiler; - } - - protected VortexCompiler MakeCompiler() - { - return new VortexCompiler( - game: utils.Game, - gamePath: utils.GameFolder, - vortexFolder: VortexCompiler.TypicalVortexFolder(), - downloadsFolder: VortexCompiler.RetrieveDownloadLocation(utils.Game), - stagingFolder: VortexCompiler.RetrieveStagingLocation(utils.Game), - outputFile: $"test{Consts.ModListExtension}"); - } - - protected async Task CompileAndInstall() - { - var vortexCompiler = await ConfigureAndRunCompiler(); - await Install(vortexCompiler); - return vortexCompiler.ModList; - } - - protected async Task Install(VortexCompiler vortexCompiler) - { - var modList = AInstaller.LoadFromFile(vortexCompiler.ModListOutputFile); - var installer = new MO2Installer( - archive: vortexCompiler.ModListOutputFile, - modList: modList, - outputFolder: utils.InstallFolder, - downloadFolder: utils.DownloadsFolder, - parameters: SystemParametersConstructor.Create()) - { - GameFolder = utils.GameFolder, - }; - await installer.Begin(); - } - } -} diff --git a/Wabbajack.Test/VortexTests.cs b/Wabbajack.Test/VortexTests.cs deleted file mode 100644 index bf475cbf..00000000 --- a/Wabbajack.Test/VortexTests.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Wabbajack.Test -{ - [TestClass] - public class VortexTests : AVortexCompilerTest - { - // TODO: figure out what games we want installed on the test server for this - /* - [TestMethod] - public void TestVortexStackSerialization() - { - utils.AddMod("test"); - utils.Configure(); - - var vortexCompiler = ConfigureAndRunCompiler(); - vortexCompiler.StagingFolder = "vortex_staging"; - var stack = vortexCompiler.MakeStack(); - - var serialized = Serialization.Serialize(stack); - var rounded = Serialization.Serialize(Serialization.Deserialize(serialized, vortexCompiler)); - - Assert.AreEqual(serialized, rounded); - Assert.IsNotNull(vortexCompiler.GetStack()); - - } - */ - } -} diff --git a/Wabbajack.Test/Wabbajack.Test.csproj b/Wabbajack.Test/Wabbajack.Test.csproj index 95c3598b..c5ad8b23 100644 --- a/Wabbajack.Test/Wabbajack.Test.csproj +++ b/Wabbajack.Test/Wabbajack.Test.csproj @@ -13,9 +13,7 @@ - - diff --git a/Wabbajack/Resources/ResourceLinks.cs b/Wabbajack/Resources/ResourceLinks.cs index f7b54b3d..8949c024 100644 --- a/Wabbajack/Resources/ResourceLinks.cs +++ b/Wabbajack/Resources/ResourceLinks.cs @@ -14,8 +14,6 @@ namespace Wabbajack UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/Wabba_Ded.png")).Stream)); public static Lazy MO2Button { get; } = new Lazy(() => UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/MO2Button.png")).Stream)); - public static Lazy VortexButton { get; } = new Lazy(() => - UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/VortexButton.png")).Stream)); public static Lazy MiddleMouseButton { get; } = new Lazy(() => UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/middle_mouse_button.png")).Stream)); } diff --git a/Wabbajack/Settings.cs b/Wabbajack/Settings.cs index 5c206107..1d2671d9 100644 --- a/Wabbajack/Settings.cs +++ b/Wabbajack/Settings.cs @@ -87,7 +87,6 @@ namespace Wabbajack public ModManager LastCompiledModManager { get; set; } public AbsolutePath OutputLocation { get; set; } public MO2CompilationSettings MO2Compilation { get; } = new MO2CompilationSettings(); - public VortexCompilationSettings VortexCompilation { get; } = new VortexCompilationSettings(); } [JsonObject(MemberSerialization.OptOut)] @@ -134,17 +133,4 @@ namespace Wabbajack public Dictionary ModlistSettings { get; } = new Dictionary(); } - public class VortexCompilationSettings - { - public Game LastCompiledGame { get; set; } - public Dictionary ModlistSettings { get; } = new Dictionary(); - } - - public class VortexGameSettings - { - public string GameLocation { get; set; } - public string DownloadLocation { get; set; } - public string StagingLocation { get; set; } - public CompilationModlistSettings ModlistSettings { get; } = new CompilationModlistSettings(); - } } diff --git a/Wabbajack/View Models/Compilers/CompilerVM.cs b/Wabbajack/View Models/Compilers/CompilerVM.cs index b6441579..2593c72e 100644 --- a/Wabbajack/View Models/Compilers/CompilerVM.cs +++ b/Wabbajack/View Models/Compilers/CompilerVM.cs @@ -102,10 +102,6 @@ namespace Wabbajack { case ModManager.MO2: return new MO2CompilerVM(this); - /* - case ModManager.Vortex: - return new VortexCompilerVM(this); - */ default: return null; } diff --git a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs deleted file mode 100644 index 10777fc4..00000000 --- a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs +++ /dev/null @@ -1,219 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Threading.Tasks; -using System.Windows.Input; -using DynamicData.Binding; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using Wabbajack.Common; -using Wabbajack.Common.StoreHandlers; -using Wabbajack.Lib; - -namespace Wabbajack -{ - public class VortexCompilerVM : ViewModel, ISubCompilerVM - { - public CompilerVM Parent { get; } - - private readonly VortexCompilationSettings _settings; - - private readonly ObservableAsPropertyHelper _modListSettings; - public ModlistSettingsEditorVM ModlistSettings => _modListSettings.Value; - - private static readonly ObservableCollectionExtended _gameOptions = new ObservableCollectionExtended( - EnumExt.GetValues() - .Where(g => VortexCompiler.IsActiveVortexGame(g)) - .Select(g => new GameVM(g)) - .OrderBy(g => g.DisplayName)); - - public ObservableCollectionExtended GameOptions => _gameOptions; - - [Reactive] - public ACompiler ActiveCompilation { get; private set; } - - [Reactive] - public GameVM SelectedGame { get; set; } - - [Reactive] - public FilePickerVM GameLocation { get; set; } - - [Reactive] - public FilePickerVM DownloadsLocation { get; set; } - - [Reactive] - public FilePickerVM StagingLocation { get; set; } - - public ICommand FindGameInSteamCommand { get; } - - public ICommand FindGameInGogCommand { get; } - - [Reactive] - public StatusUpdateTracker StatusTracker { get; private set; } - - public IObservable CanCompile { get; } - - public VortexCompilerVM(CompilerVM parent) - { - Parent = parent; - GameLocation = new FilePickerVM() - { - ExistCheckOption = FilePickerVM.CheckOptions.On, - PathType = FilePickerVM.PathTypeOptions.Folder, - PromptTitle = "Select Game Folder Location" - }; - DownloadsLocation = new FilePickerVM() - { - ExistCheckOption = FilePickerVM.CheckOptions.On, - PathType = FilePickerVM.PathTypeOptions.Folder, - PromptTitle = "Select Downloads Folder" - }; - StagingLocation = new FilePickerVM() - { - ExistCheckOption = FilePickerVM.CheckOptions.On, - PathType = FilePickerVM.PathTypeOptions.Folder, - PromptTitle = "Select Staging Folder" - }; - - // Load custom ModList settings when game type changes - _modListSettings = (this).WhenAny(x => x.SelectedGame) - .Select(game => - { - if (game == null) return null; - var gameSettings = _settings.ModlistSettings.TryCreate(game.Game); - return new ModlistSettingsEditorVM(gameSettings.ModlistSettings); - }) - // Interject and save old while loading new - .Pairwise() - .Do(pair => - { - var (previous, current) = pair; - previous?.Save(); - current?.Init(); - }) - .Select(x => x.Current) - .ToGuiProperty(this, nameof(ModlistSettings)); - - CanCompile = Observable.CombineLatest( - this.WhenAny(x => x.GameLocation.InError), - this.WhenAny(x => x.DownloadsLocation.InError), - this.WhenAny(x => x.StagingLocation.InError), - this.WhenAny(x => x.ModlistSettings) - .Select(x => x?.InError ?? Observable.Return(false)) - .Switch(), - (g, d, s, ml) => !g && !d && !s && !ml) - .Publish() - .RefCount(); - - // Load settings - _settings = parent.MWVM.Settings.Compiler.VortexCompilation; - SelectedGame = _gameOptions.FirstOrDefault(x => x.Game == _settings.LastCompiledGame) ?? _gameOptions[0]; - parent.MWVM.Settings.SaveSignal - .Subscribe(_ => Unload()) - .DisposeWith(CompositeDisposable); - - // Load custom game settings when game type changes - (this).WhenAny(x => x.SelectedGame) - .Select(game => _settings.ModlistSettings.TryCreate(game.Game)) - .Pairwise() - .Subscribe(pair => - { - // Save old - var (previous, current) = pair; - if (previous != null) - { - previous.GameLocation = GameLocation.TargetPath; - } - - // Load new - GameLocation.TargetPath = current?.GameLocation; - if (string.IsNullOrWhiteSpace(GameLocation.TargetPath)) - { - SetGameToSteamLocation(); - } - if (string.IsNullOrWhiteSpace(GameLocation.TargetPath)) - { - SetGameToGogLocation(); - } - DownloadsLocation.TargetPath = current?.DownloadLocation; - if (string.IsNullOrWhiteSpace(DownloadsLocation.TargetPath)) - { - DownloadsLocation.TargetPath = VortexCompiler.RetrieveDownloadLocation(SelectedGame.Game); - } - StagingLocation.TargetPath = current?.StagingLocation; - if (string.IsNullOrWhiteSpace(StagingLocation.TargetPath)) - { - StagingLocation.TargetPath = VortexCompiler.RetrieveStagingLocation(SelectedGame.Game); - } - }) - .DisposeWith(CompositeDisposable); - - // Find game commands - FindGameInSteamCommand = ReactiveCommand.Create(SetGameToSteamLocation); - FindGameInGogCommand = ReactiveCommand.Create(SetGameToGogLocation); - - // Add additional criteria to download/staging folders - DownloadsLocation.AdditionalError = this.WhenAny(x => x.DownloadsLocation.TargetPath) - .Select(path => path == null ? ErrorResponse.Success : VortexCompiler.IsValidDownloadsFolder(path)); - StagingLocation.AdditionalError = this.WhenAny(x => x.StagingLocation.TargetPath) - .Select(path => path == null ? ErrorResponse.Success : VortexCompiler.IsValidBaseStagingFolder(path)); - } - - public void Unload() - { - _settings.LastCompiledGame = SelectedGame.Game; - ModlistSettings?.Save(); - } - - private void SetGameToSteamLocation() - { - GameLocation.TargetPath = StoreHandler.Instance.GetGamePath(SelectedGame.Game, StoreType.STEAM); - } - - private void SetGameToGogLocation() - { - GameLocation.TargetPath = StoreHandler.Instance.GetGamePath(SelectedGame.Game, StoreType.GOG); - } - - public async Task> Compile() - { - string outputFile = $"{ModlistSettings.ModListName}{Consts.ModListExtension}"; - if (!string.IsNullOrWhiteSpace(Parent.OutputLocation.TargetPath)) - { - outputFile = Path.Combine(Parent.OutputLocation.TargetPath, outputFile); - } - try - { - using (ActiveCompilation = new VortexCompiler( - game: SelectedGame.Game, - gamePath: GameLocation.TargetPath, - vortexFolder: VortexCompiler.TypicalVortexFolder(), - downloadsFolder: DownloadsLocation.TargetPath, - stagingFolder: StagingLocation.TargetPath, - outputFile: outputFile) - { - ModListName = ModlistSettings.ModListName, - ModListAuthor = ModlistSettings.AuthorText, - ModListDescription = ModlistSettings.Description, - ModListImage = ModlistSettings.ImagePath.TargetPath, - ModListWebsite = ModlistSettings.Website, - ModListReadme = ModlistSettings.ReadmeIsWebsite ? ModlistSettings.Readme : ModlistSettings.ReadmeFilePath.TargetPath, - ReadmeIsWebsite = ModlistSettings.ReadmeIsWebsite, - }) - { - Parent.MWVM.Settings.Performance.AttachToBatchProcessor(ActiveCompilation); - var success = await ActiveCompilation.Begin(); - return GetResponse.Create(success, ActiveCompilation.ModList); - } - } - finally - { - StatusTracker = null; - ActiveCompilation.Dispose(); - ActiveCompilation = null; - } - } - } -} diff --git a/Wabbajack/View Models/Installers/InstallerVM.cs b/Wabbajack/View Models/Installers/InstallerVM.cs index 630b321d..5ed977d0 100644 --- a/Wabbajack/View Models/Installers/InstallerVM.cs +++ b/Wabbajack/View Models/Installers/InstallerVM.cs @@ -128,8 +128,6 @@ namespace Wabbajack { case ModManager.MO2: return new MO2InstallerVM(this); - /*case ModManager.Vortex: - return new VortexInstallerVM(this);*/ default: return null; } diff --git a/Wabbajack/View Models/Installers/VortexInstallerVM.cs b/Wabbajack/View Models/Installers/VortexInstallerVM.cs deleted file mode 100644 index 2652332a..00000000 --- a/Wabbajack/View Models/Installers/VortexInstallerVM.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reactive.Linq; -using System.Text; -using System.Threading.Tasks; -using ReactiveUI; -using ReactiveUI.Fody.Helpers; -using Wabbajack.Common; -using Wabbajack.Lib; -using Wabbajack.Util; - -namespace Wabbajack -{ - public class VortexInstallerVM : ViewModel, ISubInstallerVM - { - public InstallerVM Parent { get; } - - [Reactive] - public AInstaller ActiveInstallation { get; private set; } - - private readonly ObservableAsPropertyHelper _DownloadLocation; - public string DownloadLocation => _DownloadLocation.Value; - - private readonly ObservableAsPropertyHelper _StagingLocation; - public string StagingLocation => _StagingLocation.Value; - - private readonly ObservableAsPropertyHelper _TargetGame; - public Game TargetGame => _TargetGame.Value; - - public bool SupportsAfterInstallNavigation => false; - - public int ConfigVisualVerticalOffset => 0; - - public IObservable CanInstall { get; } - - public VortexInstallerVM(InstallerVM installerVM) - { - Parent = installerVM; - - _TargetGame = installerVM.WhenAny(x => x.ModList.SourceModList.GameType) - .ToGuiProperty(this, nameof(TargetGame)); - - CanInstall = Observable.CombineLatest( - this.WhenAny(x => x.TargetGame) - .Select(game => VortexCompiler.IsActiveVortexGame(game)), - installerVM.WhenAny(x => x.ModListLocation.InError), - resultSelector: (isVortexGame, modListErr) => isVortexGame && !modListErr); - } - - public void Unload() - { - } - - public void AfterInstallNavigation() - { - throw new NotImplementedException(); - } - - public async Task Install() - { - AInstaller installer; - - var download = VortexCompiler.RetrieveDownloadLocation(TargetGame); - var staging = VortexCompiler.RetrieveStagingLocation(TargetGame); - using (installer = new VortexInstaller( - archive: Parent.ModListLocation.TargetPath, - modList: Parent.ModList.SourceModList, - outputFolder: staging, - downloadFolder: download, - parameters: SystemParametersConstructor.Create())) - { - Parent.MWVM.Settings.Performance.AttachToBatchProcessor(installer); - - return await Task.Run(async () => - { - try - { - var workTask = installer.Begin(); - ActiveInstallation = installer; - return await workTask; - } - finally - { - ActiveInstallation = null; - } - }); - } - } - - public IUserIntervention InterventionConverter(IUserIntervention intervention) => intervention; - } -} diff --git a/Wabbajack/Views/Compilers/CompilerView.xaml b/Wabbajack/Views/Compilers/CompilerView.xaml index 8121d81b..5fa4a148 100644 --- a/Wabbajack/Views/Compilers/CompilerView.xaml +++ b/Wabbajack/Views/Compilers/CompilerView.xaml @@ -197,16 +197,6 @@ - - - - - - started ? Visibility.Hidden : Visibility.Visible) .BindToStrict(this, x => x.BottomCompilerSettingsGrid.Visibility) .DisposeWith(dispose); - // Seems to go into an infinite loop between each other. Need to research a better radio button style pattern - //this.BindStrict(this.ViewModel, x => x.SelectedCompilerType, x => x.MO2CompilerButton.IsChecked, - // vmToViewConverter: type => type == ModManager.MO2, - // viewToVmConverter: isChecked => isChecked ? ModManager.MO2 : ModManager.Vortex); - //this.BindStrict(this.ViewModel, x => x.SelectedCompilerType, x => x.MO2CompilerButton.IsChecked, - // vmToViewConverter: type => type == ModManager.Vortex, - // viewToVmConverter: isChecked => isChecked ? ModManager.Vortex : ModManager.MO2); this.WhenAny(x => x.ViewModel.Compiler) .BindToStrict(this, x => x.CustomCompilerSettingsPresenter.Content) .DisposeWith(dispose); diff --git a/Wabbajack/Views/Installers/InstallationView.xaml b/Wabbajack/Views/Installers/InstallationView.xaml index 2a45dc02..26bc8c1e 100644 --- a/Wabbajack/Views/Installers/InstallationView.xaml +++ b/Wabbajack/Views/Installers/InstallationView.xaml @@ -358,11 +358,6 @@ -