From 059f2ec96fc81dcd72779a1fa40f4bed00e0a141 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Sat, 2 May 2020 15:09:29 -0600 Subject: [PATCH] Can source game downloads from the game folder --- Wabbajack.Common/GameMetaData.cs | 2 +- .../StoreHandlers/SteamHandler.cs | 2 +- Wabbajack.Lib/ACompiler.cs | 10 ++++ .../Downloaders/AbstractDownloadState.cs | 5 ++ .../Downloaders/GameFileSourceDownloader.cs | 8 +++- Wabbajack.Lib/MO2Compiler.cs | 46 ++++++++++++++----- Wabbajack.Test/SanityTests.cs | 21 +++++++++ 7 files changed, 80 insertions(+), 14 deletions(-) diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index 3744f62c..e5e2e4f1 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -85,7 +85,7 @@ namespace Wabbajack.Common public AbsolutePath? TryGetGameLocation() { - return Consts.TestMode ? AbsolutePath.GetCurrentDirectory() : StoreHandler.Instance.TryGetGamePath(Game); + return StoreHandler.Instance.TryGetGamePath(Game); } public bool TryGetGameLocation(out AbsolutePath path) diff --git a/Wabbajack.Common/StoreHandlers/SteamHandler.cs b/Wabbajack.Common/StoreHandlers/SteamHandler.cs index 3fec8415..fda12882 100644 --- a/Wabbajack.Common/StoreHandlers/SteamHandler.cs +++ b/Wabbajack.Common/StoreHandlers/SteamHandler.cs @@ -155,7 +155,7 @@ namespace Wabbajack.Common.StoreHandlers if (!l.ContainsCaseInsensitive("\"installdir\"")) return; - var path = new RelativePath($"common//{GetVdfValue(l)}").RelativeTo(u); + var path = new RelativePath("common").Combine(GetVdfValue(l)).RelativeTo(u); if (path.Exists) game.Path = path; }); diff --git a/Wabbajack.Lib/ACompiler.cs b/Wabbajack.Lib/ACompiler.cs index 9d0c694b..e11b6c4a 100644 --- a/Wabbajack.Lib/ACompiler.cs +++ b/Wabbajack.Lib/ACompiler.cs @@ -4,6 +4,7 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Reactive.Subjects; +using System.Text; using System.Threading.Tasks; using Wabbajack.Common; using Wabbajack.Lib.CompilationSteps; @@ -100,6 +101,15 @@ namespace Wabbajack.Lib return id; } + + internal async Task<(RelativePath, AbsolutePath)> IncludeString(string str) + { + var id = IncludeId(); + var fullPath = ModListOutputFolder.Combine(id); + await fullPath.WriteAllTextAsync(str); + return (id, fullPath); + } + public async Task GatherMetaData() { Utils.Log($"Getting meta data for {SelectedArchives.Count} archives"); diff --git a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs index ebfc5b32..381e9aa3 100644 --- a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs +++ b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs @@ -94,5 +94,10 @@ namespace Wabbajack.Lib.Downloaders public abstract string? GetManifestURL(Archive a); public abstract string[] GetMetaIni(); + + public string GetMetaIniString() + { + return string.Join("\n", GetMetaIni()); + } } } diff --git a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs index 4268033e..25f5b5fa 100644 --- a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs @@ -46,13 +46,18 @@ namespace Wabbajack.Lib.Downloaders public Game Game { get; set; } public RelativePath GameFile { get; set; } public Hash Hash { get; set; } - public string GameVersion { get; } + public string GameVersion { get; set; } = ""; public State(string gameVersion) { GameVersion = gameVersion; } + public State() + { + + } + [JsonIgnore] internal AbsolutePath SourcePath => Game.MetaData().GameLocation().Combine(GameFile); @@ -93,6 +98,7 @@ namespace Wabbajack.Lib.Downloaders { return new[] {"[General]", $"gameName={Game.MetaData().MO2ArchiveName}", $"gameFile={GameFile}"}; } + } } } diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 5a7d313a..9cef5c1f 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -1,24 +1,17 @@ using Compression.BSA; using System; -using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using Alphaleonis.Win32.Filesystem; using Wabbajack.Common; using Wabbajack.Lib.CompilationSteps; using Wabbajack.Lib.Downloaders; using Wabbajack.Lib.FileUploader; -using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.Validation; -using Directory = Alphaleonis.Win32.Filesystem.Directory; -using File = Alphaleonis.Win32.Filesystem.File; -using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; -using Game = Wabbajack.Common.Game; +using Wabbajack.VirtualFileSystem; using Path = Alphaleonis.Win32.Filesystem.Path; namespace Wabbajack.Lib @@ -105,7 +98,7 @@ namespace Wabbajack.Lib var roots = new List { - MO2Folder, GamePath, MO2DownloadsFolder + MO2Folder, GamePath, MO2DownloadsFolder, CompilingGame.GameLocation() }; // TODO: make this generic so we can add more paths @@ -172,6 +165,7 @@ namespace Wabbajack.Lib UpdateTracker.NextStep("Pre-validating Archives"); + // Find all Downloads IndexedArchives = (await MO2DownloadsFolder.EnumerateFiles() .Where(f => f.WithExtension(Consts.MetaFileExtension).Exists) .PMap(Queue, async f => new IndexedArchive(VFS.Index.ByRootPath[f]) @@ -180,9 +174,37 @@ namespace Wabbajack.Lib IniData = f.WithExtension(Consts.MetaFileExtension).LoadIniFile(), Meta = await f.WithExtension(Consts.MetaFileExtension).ReadAllTextAsync() })).ToList(); + + + var stockGameFolder = CompilingGame.GameLocation(); + foreach (var (relativePath, hash) in await ClientAPI.GetGameFiles(CompilingGame.Game, Version.Parse(CompilingGame.InstalledVersion))) + { + if (!VFS.Index.ByRootPath.TryGetValue(relativePath.RelativeTo(stockGameFolder), out var virtualFile)) + continue; + if (virtualFile.Hash != hash) + { + Utils.Log( + $"File {relativePath} int the game folder appears to be modified, it will not be used during compilation"); + continue; + } + var state = new GameFileSourceDownloader.State + { + Game = CompilingGame.Game, GameVersion = CompilingGame.InstalledVersion, GameFile = relativePath + }; + Utils.Log($"Adding Game file: {relativePath}"); + IndexedArchives.Add(new IndexedArchive(virtualFile) + { + Name = (string)relativePath.FileName, + IniData = state.GetMetaIniString().LoadIniString(), + Meta = state.GetMetaIniString() + }); + } + + + await CleanInvalidArchives(); UpdateTracker.NextStep("Finding Install Files"); @@ -395,11 +417,13 @@ namespace Wabbajack.Lib await SelectedArchives.PMap(Queue, async a => { var source = MO2DownloadsFolder.Combine(a.Name + Consts.MetaFileExtension); + var ini = a.State.GetMetaIniString(); + var (id, fullPath) = await IncludeString(ini); InstallDirectives.Add(new ArchiveMeta { - SourceDataID = await IncludeFile(source), + SourceDataID = id, Size = source.Size, - Hash = await source.FileHashAsync(), + Hash = await fullPath.FileHashAsync(), To = source.FileName }); }); diff --git a/Wabbajack.Test/SanityTests.cs b/Wabbajack.Test/SanityTests.cs index f1b58015..f6279b49 100644 --- a/Wabbajack.Test/SanityTests.cs +++ b/Wabbajack.Test/SanityTests.cs @@ -421,6 +421,27 @@ namespace Wabbajack.Test utils.VerifyInstalledFile(mod, @"baz.bsa"); } + + [Fact] + public async Task CanSourceFilesFromStockGameFiles() + { + Consts.TestMode = false; + + var profile = utils.AddProfile(); + var mod = utils.AddMod(); + var skyrimExe = utils.AddModFile(mod, @"Data\test.exe", 10); + + await Game.SkyrimSpecialEdition.MetaData().GameLocation().Combine("SkyrimSE.exe").CopyToAsync(skyrimExe); + + await utils.Configure(); + + await CompileAndInstall(profile); + + utils.VerifyInstalledFile(mod, @"Data\test.exe"); + + Consts.TestMode = true; + + } [Fact] public async Task NoMatchIncludeIncludesNonMatchingFiles()