Ejemplo n.º 1
0
        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));
            });
        }
Ejemplo n.º 2
0
        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();
            });
        }
Ejemplo n.º 3
0
 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));
     });
 }
Ejemplo n.º 4
0
        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;
        }
Ejemplo n.º 5
0
        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);
        }
Ejemplo n.º 6
0
        /// <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();
        }