protected override async Task <bool> _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 <string> { 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"); if (Directory.Exists(ModListOutputFolder)) { Utils.DeleteDirectory(ModListOutputFolder); } Directory.CreateDirectory(ModListOutputFolder); UpdateTracker.NextStep("Finding Install Files"); 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 <NoMatch>().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 ?? "", Archives = SelectedArchives.ToList(), ModManager = ModManager.Vortex, Directives = InstallDirectives, GameType = Game }; UpdateTracker.NextStep("Running Validation"); await ValidateModlist.RunValidation(Queue, ModList); UpdateTracker.NextStep("Generating Report"); GenerateManifest(); UpdateTracker.NextStep("Exporting ModList"); ExportModList(); ResetMembers(); UpdateTracker.NextStep("Done Building ModList"); return(true); }