public async Task DownloadMissingArchives(List <Archive> missing, bool download = true) { if (download) { foreach (var a in missing.Where(a => a.State.GetType() == typeof(ManualDownloader.State))) { var outputPath = DownloadFolder.Combine(a.Name); await a.State.Download(a, outputPath); } } await missing.Where(a => a.State.GetType() != typeof(ManualDownloader.State)) .PMap(Queue, async archive => { Info($"Downloading {archive.Name}"); var outputPath = DownloadFolder.Combine(archive.Name); if (download) { if (outputPath.Exists) { var origName = Path.GetFileNameWithoutExtension(archive.Name); var ext = Path.GetExtension(archive.Name); var uniqueKey = archive.State.PrimaryKeyString.StringSha256Hex(); outputPath = DownloadFolder.Combine(origName + "_" + uniqueKey + "_" + ext); outputPath.Delete(); } } return(await DownloadArchive(archive, download, outputPath)); }); }
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 <SteamMeta>() .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 InstallIncludedDownloadMetas() { await ModList.Directives .OfType <ArchiveMeta>() .PMap(Queue, async directive => { Status($"Writing included .meta file {directive.To}"); var outPath = DownloadFolder.Combine(directive.To); if (outPath.IsFile) { outPath.Delete(); } await outPath.WriteAllBytesAsync(await LoadBytesFromPath(directive.SourceDataID)); }); }
public async Task<bool> DownloadArchive(Archive archive, bool download, AbsolutePath? destination = null) { try { if (destination == null) destination = DownloadFolder.Combine(archive.Name); await DownloadDispatcher.DownloadWithPossibleUpgrade(archive, destination.Value); } catch (Exception ex) { Utils.Log($"Download error for file {archive.Name}"); Utils.Log(ex.ToString()); return false; } return false; }
public async Task <bool> DownloadArchive(Archive archive, bool download, AbsolutePath?destination = null) { try { destination ??= DownloadFolder.Combine(archive.Name); var result = await DownloadDispatcher.DownloadWithPossibleUpgrade(archive, destination.Value); if (result == DownloadDispatcher.DownloadResult.Update) { await destination.Value.MoveToAsync(destination.Value.Parent.Combine(archive.Hash.ToHex())); } } catch (Exception ex) { Utils.Log($"Download error for file {archive.Name}"); Utils.Log(ex.ToString()); return(false); } return(false); }
/// <summary> /// The user may already have some files in the OutputFolder. If so we can go through these and /// figure out which need to be updated, deleted, or left alone /// </summary> public async Task OptimizeModlist() { Utils.Log("Optimizing ModList directives"); // Clone the ModList so our changes don't modify the original data ModList = ModList.Clone(); var indexed = ModList.Directives.ToDictionary(d => d.To); var profileFolder = OutputFolder.Combine("profiles"); var savePath = (RelativePath)"saves"; UpdateTracker.NextStep("Looking for files to delete"); await OutputFolder.EnumerateFiles() .PMap(Queue, UpdateTracker, async f => { var relativeTo = f.RelativeTo(OutputFolder); if (indexed.ContainsKey(relativeTo) || f.InFolder(DownloadFolder)) { return; } if (f.InFolder(profileFolder) && f.Parent.FileName == savePath) { return; } Utils.Log($"Deleting {relativeTo} it's not part of this ModList"); await f.DeleteAsync(); }); Utils.Log("Cleaning empty folders"); var expectedFolders = indexed.Keys .Select(f => f.RelativeTo(OutputFolder)) // We ignore the last part of the path, so we need a dummy file name .Append(DownloadFolder.Combine("_")) .Where(f => f.InFolder(OutputFolder)) .SelectMany(path => { // Get all the folders and all the folder parents // so for foo\bar\baz\qux.txt this emits ["foo", "foo\\bar", "foo\\bar\\baz"] var split = ((string)path.RelativeTo(OutputFolder)).Split('\\'); return(Enumerable.Range(1, split.Length - 1).Select(t => string.Join("\\", split.Take(t)))); }) .Distinct() .Select(p => OutputFolder.Combine(p)) .ToHashSet(); try { var toDelete = OutputFolder.EnumerateDirectories(true) .Where(p => !expectedFolders.Contains(p)) .OrderByDescending(p => ((string)p).Length) .ToList(); foreach (var dir in toDelete) { await dir.DeleteDirectory(dontDeleteIfNotEmpty : true); } } catch (Exception) { // ignored because it's not worth throwing a fit over Utils.Log("Error when trying to clean empty folders. This doesn't really matter."); } var existingfiles = OutputFolder.EnumerateFiles().ToHashSet(); UpdateTracker.NextStep("Looking for unmodified files"); (await indexed.Values.PMap(Queue, UpdateTracker, async d => { // Bit backwards, but we want to return null for // all files we *want* installed. We return the files // to remove from the install list. var path = OutputFolder.Combine(d.To); if (!existingfiles.Contains(path)) { return(null); } return(await path.FileHashCachedAsync() == d.Hash ? d : null); })) .Do(d => { if (d != null) { indexed.Remove(d.To); } }); UpdateTracker.NextStep("Updating ModList"); Utils.Log($"Optimized {ModList.Directives.Count} directives to {indexed.Count} required"); var requiredArchives = indexed.Values.OfType <FromArchive>() .GroupBy(d => d.ArchiveHashPath.BaseHash) .Select(d => d.Key) .ToHashSet(); ModList.Archives = ModList.Archives.Where(a => requiredArchives.Contains(a.Hash)).ToList(); ModList.Directives = indexed.Values.ToList(); }