From 528b1daded6de3f77d2593408f43672a9e63e623 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Sat, 4 Jan 2020 22:07:00 -0700 Subject: [PATCH 01/26] Delete empty folders after install. Ends up being a bit tricky because folders might exist that weren't part of the original list. So we have to find all the folders, and then find the ones that aren't part of the folders to be created by the installer, and we delete those folders. --- Wabbajack.Lib/AInstaller.cs | 24 ++++++++++++++++++++++++ Wabbajack.Test/SanityTests.cs | 7 +++++++ 2 files changed, 31 insertions(+) diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index ce4550d4..27efbcb0 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -377,6 +377,30 @@ namespace Wabbajack.Lib .Where(d => d != null) .Do(d => indexed.Remove(d.To)); + Utils.Log("Cleaning empty folders"); + var expectedFolders = indexed.Keys.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 = path.Split('\\'); + return Enumerable.Range(1, split.Length - 1).Select(t => string.Join("\\", split.Take(t))); + }).Distinct() + .Select(p => Path.Combine(OutputFolder, p)) + .ToHashSet(); + + try + { + Directory.EnumerateDirectories(OutputFolder, DirectoryEnumerationOptions.Recursive) + .Where(p => !expectedFolders.Contains(p)) + .OrderByDescending(p => p.Length) + .Do(p => Directory.Delete(p)); + } + 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."); + } + UpdateTracker.NextStep("Updating Modlist"); Utils.Log($"Optimized {ModList.Directives.Count} directives to {indexed.Count} required"); var requiredArchives = indexed.Values.OfType() diff --git a/Wabbajack.Test/SanityTests.cs b/Wabbajack.Test/SanityTests.cs index 411ad9d3..e2f9c732 100644 --- a/Wabbajack.Test/SanityTests.cs +++ b/Wabbajack.Test/SanityTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -87,6 +88,11 @@ namespace Wabbajack.Test var extra_path = utils.PathOfInstalledFile(mod, @"something_i_made.foo"); File.WriteAllText(extra_path, "bleh"); + var extra_folder = Path.Combine(Path.GetDirectoryName(utils.PathOfInstalledFile(mod, @"something_i_made.foo")), "folder_i_made"); + Directory.CreateDirectory(extra_folder); + + Assert.IsTrue(Directory.Exists(extra_folder)); + var unchanged_modified = File.GetLastWriteTime(unchanged_path); var modified_modified = File.GetLastWriteTime(modified_path); @@ -105,6 +111,7 @@ namespace Wabbajack.Test Assert.AreEqual(unchanged_modified, File.GetLastWriteTime(unchanged_path)); Assert.AreNotEqual(modified_modified, File.GetLastWriteTime(modified_path)); Assert.IsFalse(File.Exists(extra_path)); + Assert.IsFalse(Directory.Exists(extra_folder)); } From 5f969a00dfbce3c29645b20e041168c0e9ff0c92 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Sat, 4 Jan 2020 22:38:08 -0700 Subject: [PATCH 02/26] Reworked the LL downloader to abstract commonly used items in an abstract class --- .../AbstractNeedsLoginDownloader.cs | 142 ++++++++++++++++++ .../Downloaders/LoversLabDownloader.cs | 108 ++----------- Wabbajack.Lib/Wabbajack.Lib.csproj | 1 + .../View Models/UserInterventionHandlers.cs | 4 +- 4 files changed, 161 insertions(+), 94 deletions(-) create mode 100644 Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs diff --git a/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs new file mode 100644 index 00000000..61a83a81 --- /dev/null +++ b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs @@ -0,0 +1,142 @@ +using System; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Reactive.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using ReactiveUI; +using Wabbajack.Common; +using Wabbajack.Common.StatusFeed; +using Wabbajack.Lib.LibCefHelpers; +using Wabbajack.Lib.WebAutomation; + +namespace Wabbajack.Lib.Downloaders +{ + public abstract class AbstractNeedsLoginDownloader : INeedsLogin + { + private readonly Uri _loginUri; + private readonly string _encryptedKeyName; + private readonly string _cookieDomain; + private readonly string _cookieName; + protected HttpClient AuthedClient; + + /// + /// Sets up all the login facilites needed for a INeedsLogin downloader based on having the user log + /// in via a browser + /// + /// The URI to preset for logging in + /// The name of the encrypted JSON key in which to store cookies + /// The cookie domain to scan + /// The cookie name to wait for + public AbstractNeedsLoginDownloader(Uri loginUri, + string encryptedKeyName, + string cookieDomain, + string cookieName) + { + _loginUri = loginUri; + _encryptedKeyName = encryptedKeyName; + _cookieDomain = cookieDomain; + _cookieName = cookieName; + + TriggerLogin = ReactiveCommand.CreateFromTask( + execute: () => Utils.CatchAndLog(async () => await Utils.Log(new RequestSiteLogin(this)).Task), + canExecute: IsLoggedIn.Select(b => !b).ObserveOn(RxApp.MainThreadScheduler)); + ClearLogin = ReactiveCommand.Create( + execute: () => Utils.CatchAndLog(() => Utils.DeleteEncryptedJson(_encryptedKeyName)), + canExecute: IsLoggedIn.ObserveOn(RxApp.MainThreadScheduler)); + } + + public ICommand TriggerLogin { get; } + public ICommand ClearLogin { get; } + public IObservable IsLoggedIn => Utils.HaveEncryptedJsonObservable(_encryptedKeyName); + public abstract string SiteName { get; } + public virtual string MetaInfo { get; } + public abstract Uri SiteURL { get; } + public virtual Uri IconUri { get; } + + protected virtual async Task WhileWaiting(IWebDriver browser) + { + } + + public async Task GetAndCacheCookies(IWebDriver browser, Action updateStatus, CancellationToken cancel) + { + updateStatus($"Please Log Into {SiteName}"); + await browser.NavigateTo(_loginUri); + var cookies = new Helpers.Cookie[0]; + while (true) + { + cancel.ThrowIfCancellationRequested(); + await WhileWaiting(browser); + cookies = (await browser.GetCookies(_cookieDomain)); + if (cookies.FirstOrDefault(c => c.Name == _cookieName) != null) + break; + await Task.Delay(500, cancel); + } + + cookies.ToEcryptedJson(_encryptedKeyName); + + return cookies; + } + + public async Task GetAuthedClient() + { + Helpers.Cookie[] cookies; + try + { + cookies = Utils.FromEncryptedJson(_encryptedKeyName); + if (cookies != null) + return Helpers.GetClient(cookies, SiteURL.ToString()); + } + catch (FileNotFoundException) { } + + cookies = await Utils.Log(new RequestSiteLogin(this)).Task; + return Helpers.GetClient(cookies, SiteURL.ToString()); + } + + public async Task Prepare() + { + AuthedClient = (await GetAuthedClient()) ?? throw new NotLoggedInError(this); + } + + public class NotLoggedInError : Exception + { + public AbstractNeedsLoginDownloader Downloader { get; } + public NotLoggedInError(AbstractNeedsLoginDownloader downloader) : base( + $"Not logged into {downloader.SiteName}, can't continue") + { + Downloader = downloader; + } + } + + + public class RequestSiteLogin : AUserIntervention + { + public AbstractNeedsLoginDownloader Downloader { get; } + public RequestSiteLogin(AbstractNeedsLoginDownloader downloader) + { + Downloader = downloader; + } + public override string ShortDescription => $"Getting {Downloader.SiteName} Login"; + public override string ExtendedDescription { get; } + + private readonly TaskCompletionSource _source = new TaskCompletionSource(); + public Task Task => _source.Task; + + public void Resume(Helpers.Cookie[] cookies) + { + Handled = true; + _source.SetResult(cookies); + } + + public override void Cancel() + { + Handled = true; + _source.TrySetCanceled(); + } + } + } + + +} diff --git a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs index 1802b605..87d4edf4 100644 --- a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs +++ b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using System.Web; using System.Windows.Input; +using CefSharp; using ReactiveUI; using Wabbajack.Common; using Wabbajack.Lib.LibCefHelpers; @@ -20,32 +21,17 @@ using File = Alphaleonis.Win32.Filesystem.File; namespace Wabbajack.Lib.Downloaders { - public class LoversLabDownloader : IDownloader, INeedsLogin + public class LoversLabDownloader : AbstractNeedsLoginDownloader, IDownloader { - internal HttpClient _authedClient; - - #region INeedsDownload - - public ICommand TriggerLogin { get; } - public ICommand ClearLogin { get; } - public IObservable IsLoggedIn => Utils.HaveEncryptedJsonObservable("loverslabcookies"); - public string SiteName => "Lovers Lab"; - public string MetaInfo => ""; - public Uri SiteURL => new Uri("https://loverslab.com"); - public Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico"); - - + public override string SiteName => "Lovers Lab"; + public override Uri SiteURL => new Uri("https://loverslab.com"); + public override Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico"); #endregion - public LoversLabDownloader() + public LoversLabDownloader() : base(new Uri("https://www.loverslab.com/login"), + "loverslabcookies", "loverslab.com", "ips4_member_id") { - TriggerLogin = ReactiveCommand.CreateFromTask( - execute: () => Utils.CatchAndLog(async () => await Utils.Log(new RequestLoversLabLogin()).Task), - canExecute: IsLoggedIn.Select(b => !b).ObserveOn(RxApp.MainThreadScheduler)); - ClearLogin = ReactiveCommand.Create( - execute: () => Utils.CatchAndLog(() => Utils.DeleteEncryptedJson("loverslabcookies")), - canExecute: IsLoggedIn.ObserveOn(RxApp.MainThreadScheduler)); } @@ -62,58 +48,17 @@ namespace Wabbajack.Lib.Downloaders FileName = file }; } - - public async Task Prepare() + protected override async Task WhileWaiting(IWebDriver browser) { - _authedClient = (await GetAuthedClient()) ?? throw new Exception("not logged into LL, TODO"); - } - - public static async Task GetAndCacheLoversLabCookies(IWebDriver browser, Action updateStatus, CancellationToken cancel) - { - updateStatus("Please Log Into Lovers Lab"); - await browser.NavigateTo(new Uri("https://www.loverslab.com/login")); - async Task CleanAds() - { - try - { - await browser.EvaluateJavaScript( - "document.querySelectorAll(\".ll_adblock\").forEach(function (itm) { itm.innerHTML = \"\";});"); - } - catch (Exception ex) - { - Utils.Error(ex); - } - return false; - } - var cookies = new Helpers.Cookie[0]; - while (true) - { - cancel.ThrowIfCancellationRequested(); - await CleanAds(); - cookies = (await browser.GetCookies("loverslab.com")); - if (cookies.FirstOrDefault(c => c.Name == "ips4_member_id") != null) - break; - await Task.Delay(500, cancel); - } - - cookies.ToEcryptedJson("loverslabcookies"); - - return cookies; - } - - public async Task GetAuthedClient() - { - Helpers.Cookie[] cookies; try { - cookies = Utils.FromEncryptedJson("loverslabcookies"); - if (cookies != null) - return Helpers.GetClient(cookies, "https://www.loverslab.com"); + await browser.EvaluateJavaScript( + "document.querySelectorAll(\".ll_adblock\").forEach(function (itm) { itm.innerHTML = \"\";});"); + } + catch (Exception ex) + { + Utils.Error(ex); } - catch (FileNotFoundException) { } - - cookies = await Utils.Log(new RequestLoversLabLogin()).Task; - return Helpers.GetClient(cookies, "https://www.loverslab.com"); } public class State : AbstractDownloadState @@ -141,7 +86,7 @@ namespace Wabbajack.Lib.Downloaders { var result = DownloadDispatcher.GetInstance(); TOP: - var html = await result._authedClient.GetStringAsync( + var html = await result.AuthedClient.GetStringAsync( $"https://www.loverslab.com/files/file/{FileName}/?do=download&r={FileID}"); var pattern = new Regex("(?<=csrfKey=).*(?=[&\"\'])"); @@ -153,7 +98,7 @@ namespace Wabbajack.Lib.Downloaders var url = $"https://www.loverslab.com/files/file/{FileName}/?do=download&r={FileID}&confirm=1&t=1&csrfKey={csrfKey}"; - var streamResult = await result._authedClient.GetAsync(url); + var streamResult = await result.AuthedClient.GetAsync(url); if (streamResult.StatusCode != HttpStatusCode.OK) { Utils.Error(new InvalidOperationException(), $"LoversLab servers reported an error for file: {FileID}"); @@ -208,25 +153,4 @@ namespace Wabbajack.Lib.Downloaders } } - - public class RequestLoversLabLogin : AUserIntervention - { - public override string ShortDescription => "Getting LoversLab information"; - public override string ExtendedDescription { get; } - - private readonly TaskCompletionSource _source = new TaskCompletionSource(); - public Task Task => _source.Task; - - public void Resume(Helpers.Cookie[] cookies) - { - Handled = true; - _source.SetResult(cookies); - } - - public override void Cancel() - { - Handled = true; - _source.TrySetCanceled(); - } - } } diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index a78d73b3..93863e14 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -123,6 +123,7 @@ + diff --git a/Wabbajack/View Models/UserInterventionHandlers.cs b/Wabbajack/View Models/UserInterventionHandlers.cs index 7a2ef7cd..c88fa4e4 100644 --- a/Wabbajack/View Models/UserInterventionHandlers.cs +++ b/Wabbajack/View Models/UserInterventionHandlers.cs @@ -66,11 +66,11 @@ namespace Wabbajack c.Resume(key); }); break; - case RequestLoversLabLogin c: + case AbstractNeedsLoginDownloader.RequestSiteLogin c: await WrapBrowserJob(msg, async (vm, cancel) => { await vm.Driver.WaitForInitialized(); - var data = await LoversLabDownloader.GetAndCacheLoversLabCookies(new CefSharpWrapper(vm.Browser), m => vm.Instructions = m, cancel.Token); + var data = await c.Downloader.GetAndCacheCookies(new CefSharpWrapper(vm.Browser), m => vm.Instructions = m, cancel.Token); c.Resume(data); }); break; From dc2cc80bd08c024d63ebbeeccacd5ecc76cc150e Mon Sep 17 00:00:00 2001 From: erri120 Date: Sun, 5 Jan 2020 13:52:02 +0100 Subject: [PATCH 03/26] Created basic CLI classes --- Wabbajack.Common/CLI.cs | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 Wabbajack.Common/CLI.cs diff --git a/Wabbajack.Common/CLI.cs b/Wabbajack.Common/CLI.cs new file mode 100644 index 00000000..96fd6866 --- /dev/null +++ b/Wabbajack.Common/CLI.cs @@ -0,0 +1,74 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace Wabbajack.Common +{ + public static class CLIArguments + { + [CLIOptions("nosettings")] + public static bool NoSettings { get; set; } + + [CLIOptions("apikey")] + public static string ApiKey { get; set; } + } + + public static class CLI + { + /// + /// Parses the argument and sets the properties of + /// + /// + public static void ParseOptions(string[] args) + { + if (args.Length == 0) return; + // get all properties of the class Options + typeof(CLIArguments).GetProperties().Do(p => + { + var optionAttr = (CLIOptions[])p.GetCustomAttributes(typeof(CLIOptions)); + if (optionAttr.Length != 1) + return; + + var cur = optionAttr[0]; + if (cur == null) return; + + if (cur.Option != null && args.Any(a => a.Contains($"--{cur.Option}"))) + { + if (p.PropertyType == typeof(bool)) + { + p.SetValue(p, true); + return; + } + + // filter to get the actual argument + var filtered = args.Where(a => a.Contains($"--{cur.Option}")).ToList(); + if (filtered.Count != 1) return; + + // eg: --apikey="something" + var arg = filtered[0]; + arg = arg.Replace($"--{cur.Option}=", ""); + + // prev: --apikey="something", result: something + if (p.PropertyType == typeof(string)) + p.SetValue(p, arg); + } + + if (cur.ShortOption == 0) return; + }); + } + } + + [AttributeUsage(AttributeTargets.Property)] + public class CLIOptions : Attribute + { + // --option, long name of the option. Eg: --output + public string Option; + // -shortOption, short name of the option. Eg: -o + public char ShortOption; + + public CLIOptions(string option) + { + Option = option; + } + } +} From e929b661b5faac3e84c457c1e1731f285bf8dded Mon Sep 17 00:00:00 2001 From: erri120 Date: Sun, 5 Jan 2020 13:52:18 +0100 Subject: [PATCH 04/26] Parse arguments on start --- Wabbajack/App.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wabbajack/App.xaml.cs b/Wabbajack/App.xaml.cs index 1daefbf8..9672d5a6 100644 --- a/Wabbajack/App.xaml.cs +++ b/Wabbajack/App.xaml.cs @@ -14,7 +14,7 @@ namespace Wabbajack { public App() { - // Do initialization in MainWindow ctor + CLI.ParseOptions(Environment.GetCommandLineArgs()); } } } From 42e4bece9994a1ab54430ca443ff193cf453bac0 Mon Sep 17 00:00:00 2001 From: erri120 Date: Sun, 5 Jan 2020 14:09:02 +0100 Subject: [PATCH 05/26] Added shortOptions support --- Wabbajack.Common/CLI.cs | 53 ++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/Wabbajack.Common/CLI.cs b/Wabbajack.Common/CLI.cs index 96fd6866..ce1bb3cc 100644 --- a/Wabbajack.Common/CLI.cs +++ b/Wabbajack.Common/CLI.cs @@ -11,6 +11,9 @@ namespace Wabbajack.Common [CLIOptions("apikey")] public static string ApiKey { get; set; } + + [CLIOptions("install", ShortOption = 'i')] + public static string InstallPath { get; set; } } public static class CLI @@ -21,7 +24,7 @@ namespace Wabbajack.Common /// public static void ParseOptions(string[] args) { - if (args.Length == 0) return; + if (args.Length == 1) return; // get all properties of the class Options typeof(CLIArguments).GetProperties().Do(p => { @@ -30,32 +33,34 @@ namespace Wabbajack.Common return; var cur = optionAttr[0]; - if (cur == null) return; - - if (cur.Option != null && args.Any(a => a.Contains($"--{cur.Option}"))) - { - if (p.PropertyType == typeof(bool)) - { - p.SetValue(p, true); - return; - } + if (cur?.Option == null) return; - // filter to get the actual argument - var filtered = args.Where(a => a.Contains($"--{cur.Option}")).ToList(); - if (filtered.Count != 1) return; - - // eg: --apikey="something" - var arg = filtered[0]; - arg = arg.Replace($"--{cur.Option}=", ""); - - // prev: --apikey="something", result: something - if (p.PropertyType == typeof(string)) - p.SetValue(p, arg); - } - - if (cur.ShortOption == 0) return; + FillVariable(cur.Option, ref p, ref args, false); + FillVariable(cur.ShortOption, ref p, ref args, true); }); } + + private static void FillVariable(dynamic option, ref PropertyInfo p, ref string[] args, bool single) + { + var s = single ? $"-{option}" : $"--{option}"; + + if (!args.Any(a => a.Contains(s))) return; + + if (p.PropertyType == typeof(bool)) + { + p.SetValue(p, true); + return; + } + + var filtered = args.Where(a => a.Contains(s)).ToList(); + if (filtered.Count != 1) return; + + var arg = filtered[0]; + arg = arg.Replace($"{s}=", ""); + + if(p.PropertyType == typeof(string)) + p.SetValue(p, arg); + } } [AttributeUsage(AttributeTargets.Property)] From e149c6dbe7c68a147b999385ba42b0e0f9b7b325 Mon Sep 17 00:00:00 2001 From: erri120 Date: Sun, 5 Jan 2020 14:09:34 +0100 Subject: [PATCH 06/26] Starting From Modlist now uses CLIArguments --- Wabbajack.Common/ExtensionManager.cs | 4 ++-- Wabbajack/View Models/MainWindowVM.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Wabbajack.Common/ExtensionManager.cs b/Wabbajack.Common/ExtensionManager.cs index 1f0f5075..f8e2dd6b 100644 --- a/Wabbajack.Common/ExtensionManager.cs +++ b/Wabbajack.Common/ExtensionManager.cs @@ -19,7 +19,7 @@ namespace Wabbajack.Common { {"", "Wabbajack"}, {"FriendlyTypeName", "Wabbajack"}, - {"shell\\open\\command", "\"{appPath}\" -i \"%1\""}, + {"shell\\open\\command", "\"{appPath}\" -i=\"%1\""}, }; private static readonly Dictionary ExtList = new Dictionary @@ -34,7 +34,7 @@ namespace Wabbajack.Common var tempKey = progIDKey?.OpenSubKey("shell\\open\\command"); if (progIDKey == null || tempKey == null) return true; var value = tempKey.GetValue(""); - return value == null || value.ToString().Equals($"\"{appPath}\" -i \"%1\""); + return value == null || value.ToString().Equals($"\"{appPath}\" -i=\"%1\""); } public static bool IsAssociated() diff --git a/Wabbajack/View Models/MainWindowVM.cs b/Wabbajack/View Models/MainWindowVM.cs index 8a5f16de..ddd70b8a 100644 --- a/Wabbajack/View Models/MainWindowVM.cs +++ b/Wabbajack/View Models/MainWindowVM.cs @@ -129,16 +129,16 @@ namespace Wabbajack .Select(active => !SettingsPane.IsValueCreated || !object.ReferenceEquals(active, SettingsPane.Value)), execute: () => NavigateTo(SettingsPane.Value)); } + private static bool IsStartingFromModlist(out string modlistPath) { - string[] args = Environment.GetCommandLineArgs(); - if (args.Length != 3 || !args[1].Contains("-i")) + if (CLIArguments.InstallPath == null) { modlistPath = default; return false; } - modlistPath = args[2]; + modlistPath = CLIArguments.InstallPath; return true; } From 81069907075d3aa6bdc4527a3db0e622996a4337 Mon Sep 17 00:00:00 2001 From: erri120 Date: Sun, 5 Jan 2020 14:10:49 +0100 Subject: [PATCH 07/26] Loading settings will no use CLIArguments --- Wabbajack/Views/MainWindow.xaml.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Wabbajack/Views/MainWindow.xaml.cs b/Wabbajack/Views/MainWindow.xaml.cs index 5cf16005..5491cba0 100644 --- a/Wabbajack/Views/MainWindow.xaml.cs +++ b/Wabbajack/Views/MainWindow.xaml.cs @@ -48,9 +48,7 @@ namespace Wabbajack }).FireAndForget(); // Load settings - string[] args = Environment.GetCommandLineArgs(); - if ((args.Length > 1 && args[1] == "nosettings") - || !MainSettings.TryLoadTypicalSettings(out var settings)) + if (CLIArguments.NoSettings || !MainSettings.TryLoadTypicalSettings(out var settings)) { _settings = new MainSettings(); RunWhenLoaded(DefaultSettings); From cfa5717df36311de06dd45d722ef16286fc2a8ac Mon Sep 17 00:00:00 2001 From: erri120 Date: Sun, 5 Jan 2020 14:14:53 +0100 Subject: [PATCH 08/26] ApiKey can be encrypted via CLI --- Wabbajack.Lib/Downloaders/NexusDownloader.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Wabbajack.Lib/Downloaders/NexusDownloader.cs b/Wabbajack.Lib/Downloaders/NexusDownloader.cs index e757d272..43edb37d 100644 --- a/Wabbajack.Lib/Downloaders/NexusDownloader.cs +++ b/Wabbajack.Lib/Downloaders/NexusDownloader.cs @@ -35,6 +35,11 @@ namespace Wabbajack.Lib.Downloaders public NexusDownloader() { + if (CLIArguments.ApiKey != null) + { + CLIArguments.ApiKey.ToEcryptedJson("nexusapikey"); + } + TriggerLogin = ReactiveCommand.CreateFromTask( execute: () => Utils.CatchAndLog(NexusApiClient.RequestAndCacheAPIKey), canExecute: IsLoggedIn.Select(b => !b).ObserveOn(RxApp.MainThreadScheduler)); From 3e39ab8dbafeec13fd5be70dc18d7a376ec75d50 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Sun, 5 Jan 2020 17:21:05 -0700 Subject: [PATCH 09/26] Implement VectorPlexus support as a downloader, abstracted common IPS4 data behind an abstract class. --- .../ListValidationService.cs | 2 +- .../Downloaders/AbstractIPS4Downloader.cs | 155 ++++++++++++++++++ .../AbstractNeedsLoginDownloader.cs | 2 +- .../Downloaders/DownloadDispatcher.cs | 1 + .../Downloaders/LoversLabDownloader.cs | 112 +------------ .../Downloaders/VectorPlexusDownloader.cs | 22 +++ Wabbajack.Lib/Wabbajack.Lib.csproj | 2 + Wabbajack.Test/DownloaderTests.cs | 28 ++++ 8 files changed, 214 insertions(+), 110 deletions(-) create mode 100644 Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs create mode 100644 Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs diff --git a/Wabbajack.CacheServer/ListValidationService.cs b/Wabbajack.CacheServer/ListValidationService.cs index bcf18a93..0c717b1a 100644 --- a/Wabbajack.CacheServer/ListValidationService.cs +++ b/Wabbajack.CacheServer/ListValidationService.cs @@ -158,7 +158,7 @@ namespace Wabbajack.CacheServer using (var queue = new WorkQueue()) { - foreach (var list in modlists.Skip(2).Take(1)) + foreach (var list in modlists) { try { diff --git a/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs b/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs new file mode 100644 index 00000000..3635b549 --- /dev/null +++ b/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs @@ -0,0 +1,155 @@ +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Web; +using Newtonsoft.Json; +using Wabbajack.Common; +using Wabbajack.Lib.Validation; +using File = System.IO.File; + +namespace Wabbajack.Lib.Downloaders +{ + // IPS4 is the site used by LoversLab, VectorPlexus, etc. the general mechanics of each site are the + // same, so we can fairly easily abstract the state. + // Pass in the state type via TState + public abstract class AbstractIPS4Downloader : AbstractNeedsLoginDownloader, IDownloader + where TState : AbstractIPS4Downloader.State, new() + where TDownloader : IDownloader + { + public override string SiteName { get; } + public override Uri SiteURL { get; } + public async Task GetDownloaderState(dynamic archiveINI) + { + Uri url = DownloaderUtils.GetDirectURL(archiveINI); + if (url == null || url.Host != SiteURL.Host || !url.AbsolutePath.StartsWith("/files/file/")) return null; + var id = HttpUtility.ParseQueryString(url.Query)["r"]; + var file = url.AbsolutePath.Split('/').Last(s => s != ""); + + return new TState + { + FileID = id, + FileName = file + }; + } + + + public class State : AbstractDownloadState where TDownloader : IDownloader + { + public string FileID { get; set; } + public string FileName { get; set; } + + public override object[] PrimaryKey { get => new object[] {FileID, FileName}; } + + public override bool IsWhitelisted(ServerWhitelist whitelist) + { + return true; + } + + public override async Task Download(Archive a, string destination) + { + var stream = await ResolveDownloadStream(); + using (var file = File.OpenWrite(destination)) + { + stream.CopyTo(file); + } + } + + private async Task ResolveDownloadStream() + { + var downloader = (AbstractNeedsLoginDownloader)(object)DownloadDispatcher.GetInstance(); + + TOP: + string csrfurl; + if (FileID == null) + { + csrfurl = $"https://{downloader.SiteURL.Host}/files/file/{FileName}/?do=download"; + } + else + { + csrfurl = $"https://{downloader.SiteURL.Host}/files/file/{FileName}/?do=download&r={FileID}"; + } + var html = await downloader.AuthedClient.GetStringAsync(csrfurl); + + var pattern = new Regex("(?<=csrfKey=).*(?=[&\"\'])|(?<=csrfKey: \").*(?=[&\"\'])"); + var matches = pattern.Matches(html).Cast(); + + var csrfKey = matches.Where(m => m.Length == 32).Select(m => m.ToString()).FirstOrDefault(); + + if (csrfKey == null) + return null; + + string url; + if (FileID == null) + url = $"https://{downloader.SiteURL.Host}/files/file/{FileName}/?do=download&confirm=1&t=1&csrfKey={csrfKey}"; + else + url = $"https://{downloader.SiteURL.Host}/files/file/{FileName}/?do=download&r={FileID}&confirm=1&t=1&csrfKey={csrfKey}"; + + + var streamResult = await downloader.AuthedClient.GetAsync(url); + if (streamResult.StatusCode != HttpStatusCode.OK) + { + Utils.Error(new InvalidOperationException(), $"{downloader.SiteName} servers reported an error for file: {FileID}"); + } + + var content_type = streamResult.Content.Headers.ContentType; + + if (content_type.MediaType == "application/json") + { + // Sometimes LL hands back a json object telling us to wait until a certain time + var times = (await streamResult.Content.ReadAsStringAsync()).FromJSONString(); + var secs = times.Download - times.CurrentTime; + for (int x = 0; x < secs; x++) + { + Utils.Status($"Waiting for {secs} at the request of {downloader.SiteName}", x * 100 / secs); + await Task.Delay(1000); + } + Utils.Status("Retrying download"); + goto TOP; + } + + return await streamResult.Content.ReadAsStreamAsync(); + } + + private class WaitResponse + { + [JsonProperty("download")] + public int Download { get; set; } + [JsonProperty("currentTime")] + public int CurrentTime { get; set; } + } + + public override async Task Verify() + { + var stream = await ResolveDownloadStream(); + if (stream == null) + { + return false; + } + + stream.Close(); + return true; + } + + public override IDownloader GetDownloader() + { + return DownloadDispatcher.GetInstance(); + } + + public override string GetReportEntry(Archive a) + { + var downloader = (INeedsLogin)GetDownloader(); + return $"* {((INeedsLogin)GetDownloader()).SiteName} - [{a.Name}](https://{downloader.SiteURL.Host}/files/file/{FileName}/?do=download&r={FileID})"; + } + } + + protected AbstractIPS4Downloader(Uri loginUri, string encryptedKeyName, string cookieDomain) : + base(loginUri, encryptedKeyName, cookieDomain, "ips4_member_id") + { + } + + + } +} diff --git a/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs index 61a83a81..1bead261 100644 --- a/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs +++ b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs @@ -20,7 +20,7 @@ namespace Wabbajack.Lib.Downloaders private readonly string _encryptedKeyName; private readonly string _cookieDomain; private readonly string _cookieName; - protected HttpClient AuthedClient; + internal HttpClient AuthedClient; /// /// Sets up all the login facilites needed for a INeedsLogin downloader based on having the user log diff --git a/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs b/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs index f2524f95..9ef2f0ce 100644 --- a/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs +++ b/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs @@ -18,6 +18,7 @@ namespace Wabbajack.Lib.Downloaders new NexusDownloader(), new MediaFireDownloader(), new LoversLabDownloader(), + new VectorPlexusDownloader(), new HTTPDownloader(), new ManualDownloader(), }; diff --git a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs index 87d4edf4..9e142ad1 100644 --- a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs +++ b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs @@ -21,33 +21,18 @@ using File = Alphaleonis.Win32.Filesystem.File; namespace Wabbajack.Lib.Downloaders { - public class LoversLabDownloader : AbstractNeedsLoginDownloader, IDownloader + public class LoversLabDownloader : AbstractIPS4Downloader { #region INeedsDownload public override string SiteName => "Lovers Lab"; - public override Uri SiteURL => new Uri("https://loverslab.com"); + public override Uri SiteURL => new Uri("https://www.loverslab.com"); public override Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico"); #endregion public LoversLabDownloader() : base(new Uri("https://www.loverslab.com/login"), - "loverslabcookies", "loverslab.com", "ips4_member_id") + "loverslabcookies", "loverslab.com") { } - - - public async Task GetDownloaderState(dynamic archive_ini) - { - Uri url = DownloaderUtils.GetDirectURL(archive_ini); - if (url == null || url.Host != "www.loverslab.com" || !url.AbsolutePath.StartsWith("/files/file/")) return null; - var id = HttpUtility.ParseQueryString(url.Query)["r"]; - var file = url.AbsolutePath.Split('/').Last(s => s != ""); - - return new State - { - FileID = id, - FileName = file - }; - } protected override async Task WhileWaiting(IWebDriver browser) { try @@ -60,97 +45,8 @@ namespace Wabbajack.Lib.Downloaders Utils.Error(ex); } } - - public class State : AbstractDownloadState + public class State : State { - public string FileID { get; set; } - public string FileName { get; set; } - - public override object[] PrimaryKey { get => new object[] {FileID, FileName}; } - - public override bool IsWhitelisted(ServerWhitelist whitelist) - { - return true; - } - - public override async Task Download(Archive a, string destination) - { - var stream = await ResolveDownloadStream(); - using (var file = File.OpenWrite(destination)) - { - stream.CopyTo(file); - } - } - - private async Task ResolveDownloadStream() - { - var result = DownloadDispatcher.GetInstance(); - TOP: - var html = await result.AuthedClient.GetStringAsync( - $"https://www.loverslab.com/files/file/{FileName}/?do=download&r={FileID}"); - - var pattern = new Regex("(?<=csrfKey=).*(?=[&\"\'])"); - var csrfKey = pattern.Matches(html).Cast().Where(m => m.Length == 32).Select(m => m.ToString()).FirstOrDefault(); - - if (csrfKey == null) - return null; - - var url = - $"https://www.loverslab.com/files/file/{FileName}/?do=download&r={FileID}&confirm=1&t=1&csrfKey={csrfKey}"; - - var streamResult = await result.AuthedClient.GetAsync(url); - if (streamResult.StatusCode != HttpStatusCode.OK) - { - Utils.Error(new InvalidOperationException(), $"LoversLab servers reported an error for file: {FileID}"); - } - - var content_type = streamResult.Content.Headers.ContentType; - - if (content_type.MediaType == "application/json") - { - // Sometimes LL hands back a json object telling us to wait until a certain time - var times = (await streamResult.Content.ReadAsStringAsync()).FromJSONString(); - var secs = times.download - times.currentTime; - for (int x = 0; x < secs; x++) - { - Utils.Status($"Waiting for {secs} at the request of LoversLab", x * 100 / secs); - await Task.Delay(1000); - } - Utils.Status("Retrying download"); - goto TOP; - } - - return await streamResult.Content.ReadAsStreamAsync(); - } - - internal class WaitResponse - { - public int download { get; set; } - public int currentTime { get; set; } - } - - public override async Task Verify() - { - var stream = await ResolveDownloadStream(); - if (stream == null) - { - return false; - } - - stream.Close(); - return true; - } - - public override IDownloader GetDownloader() - { - return DownloadDispatcher.GetInstance(); - } - - public override string GetReportEntry(Archive a) - { - return $"* Lovers Lab - [{a.Name}](https://www.loverslab.com/files/file/{FileName}/?do=download&r={FileID})"; - } } - } } diff --git a/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs b/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs new file mode 100644 index 00000000..43a5d551 --- /dev/null +++ b/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs @@ -0,0 +1,22 @@ +using System; +using System.Threading.Tasks; + +namespace Wabbajack.Lib.Downloaders +{ + public class VectorPlexusDownloader : AbstractIPS4Downloader + { + #region INeedsDownload + public override string SiteName => "Vector Plexus"; + public override Uri SiteURL => new Uri("https://vectorplexus.com"); + public override Uri IconUri => new Uri("https://www.vectorplexus.com/favicon.ico"); + #endregion + + public VectorPlexusDownloader() : base(new Uri("https://vectorplexus.com/login"), + "vectorplexus", "vectorplexus.com") + { + } + public class State : State + { + } + } +} diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index 93863e14..44af5def 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -123,11 +123,13 @@ + + diff --git a/Wabbajack.Test/DownloaderTests.cs b/Wabbajack.Test/DownloaderTests.cs index 395a0be8..9d6fd0c0 100644 --- a/Wabbajack.Test/DownloaderTests.cs +++ b/Wabbajack.Test/DownloaderTests.cs @@ -310,6 +310,34 @@ namespace Wabbajack.Test Assert.AreEqual(File.ReadAllText(filename), "Cheese for Everyone!"); } + + [TestMethod] + public async Task VectorPlexusDownload() + { + await DownloadDispatcher.GetInstance().Prepare(); + var ini = @"[General] + directURL=https://vectorplexus.com/files/file/290-wabbajack-test-file"; + + var state = (AbstractDownloadState)await DownloadDispatcher.ResolveArchive(ini.LoadIniString()); + + Assert.IsNotNull(state); + + /*var url_state = DownloadDispatcher.ResolveArchive("https://www.loverslab.com/files/file/11116-test-file-for-wabbajack-integration/?do=download&r=737123&confirm=1&t=1"); + Assert.AreEqual("http://build.wabbajack.org/WABBAJACK_TEST_FILE.txt", + ((HTTPDownloader.State)url_state).Url); + */ + var converted = state.ViaJSON(); + Assert.IsTrue(await converted.Verify()); + var filename = Guid.NewGuid().ToString(); + + Assert.IsTrue(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); + + await converted.Download(new Archive { Name = "Vector Plexus Test.zip" }, filename); + + Assert.AreEqual("eSIyd+KOG3s=", Utils.FileHash(filename)); + + Assert.AreEqual(File.ReadAllText(filename), "Cheese for Everyone!"); + } [TestMethod] public async Task GameFileSourceDownload() From 38f4825099f984a2394a33e1d66d4596033b0ef6 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Sun, 5 Jan 2020 21:35:12 -0700 Subject: [PATCH 10/26] Clone the modlist so we don't delete everything on a re-install --- Wabbajack.Common/Utils.cs | 14 ++++++++++++-- Wabbajack.Lib/AInstaller.cs | 4 ++++ Wabbajack.Lib/Data.cs | 6 ++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Wabbajack.Common/Utils.cs b/Wabbajack.Common/Utils.cs index 7f80149e..afa739fc 100644 --- a/Wabbajack.Common/Utils.cs +++ b/Wabbajack.Common/Utils.cs @@ -365,16 +365,26 @@ namespace Wabbajack.Common public static void ToCERAS(this T obj, string filename, SerializerConfig config) { + byte[] final; + final = ToCERAS(obj, config); + File.WriteAllBytes(filename, final); + } + + public static byte[] ToCERAS(this T obj, SerializerConfig config) + { + byte[] final; var ceras = new CerasSerializer(config); byte[] buffer = null; ceras.Serialize(obj, ref buffer); - using(var m1 = new MemoryStream(buffer)) + + using (var m1 = new MemoryStream(buffer)) using (var m2 = new MemoryStream()) { BZip2.Compress(m1, m2, false, 9); m2.Seek(0, SeekOrigin.Begin); - File.WriteAllBytes(filename, m2.ToArray()); + final = m2.ToArray(); } + return final; } public static T FromCERAS(this Stream data, SerializerConfig config) diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index 27efbcb0..eb4de36c 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -344,6 +344,10 @@ namespace Wabbajack.Lib 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); UpdateTracker.NextStep("Looking for files to delete"); diff --git a/Wabbajack.Lib/Data.cs b/Wabbajack.Lib/Data.cs index 25c54c89..495fff61 100644 --- a/Wabbajack.Lib/Data.cs +++ b/Wabbajack.Lib/Data.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using Ceras; using Compression.BSA; @@ -120,6 +121,11 @@ namespace Wabbajack.Lib /// Whether readme is a website /// public bool ReadmeIsWebsite; + + public ModList Clone() + { + return new MemoryStream(this.ToCERAS(CerasConfig.Config)).FromCERAS(CerasConfig.Config); + } } public class Directive From 92c841f755a2f4a40cc3e7adecd127055221eeb1 Mon Sep 17 00:00:00 2001 From: erri120 Date: Mon, 6 Jan 2020 15:54:46 +0100 Subject: [PATCH 11/26] Added help argument to CLI --- Wabbajack.Common/CLI.cs | 31 ++++++++++++++++++++++++++++--- Wabbajack/App.xaml.cs | 2 ++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Wabbajack.Common/CLI.cs b/Wabbajack.Common/CLI.cs index ce1bb3cc..20c5081c 100644 --- a/Wabbajack.Common/CLI.cs +++ b/Wabbajack.Common/CLI.cs @@ -6,14 +6,17 @@ namespace Wabbajack.Common { public static class CLIArguments { - [CLIOptions("nosettings")] + [CLIOptions("nosettings", HelpText = "Don't load the saved Settings")] public static bool NoSettings { get; set; } - [CLIOptions("apikey")] + [CLIOptions("apikey", HelpText = "Manually input an Nexus api key")] public static string ApiKey { get; set; } - [CLIOptions("install", ShortOption = 'i')] + [CLIOptions("install", ShortOption = 'i', HelpText = "Install a ModList via CLI")] public static string InstallPath { get; set; } + + [CLIOptions("help", ShortOption = 'h', HelpText = "Display this message")] + public static bool Help { get; set; } } public static class CLI @@ -40,6 +43,26 @@ namespace Wabbajack.Common }); } + public static void DisplayHelpText() + { + Console.WriteLine("Wabbajack CLI Help Text"); + Console.WriteLine("{0,-20} | {1,-15} | {2,-30}", "Option", "Short Option", "Help Text"); + + typeof(CLIArguments).GetProperties().Do(p => + { + var optionAttr = (CLIOptions[])p.GetCustomAttributes(typeof(CLIOptions)); + if (optionAttr.Length != 1) + return; + + var cur = optionAttr[0]; + if (cur?.Option == null) return; + + var shortText = cur.ShortOption != 0 ? $"-{cur.ShortOption}" : ""; + var helpText = string.IsNullOrWhiteSpace(cur.HelpText) ? "" : cur.HelpText; + Console.WriteLine("{0,-20} | {1,-15} | {2,-30}", $"--{cur.Option}", shortText, helpText); + }); + } + private static void FillVariable(dynamic option, ref PropertyInfo p, ref string[] args, bool single) { var s = single ? $"-{option}" : $"--{option}"; @@ -70,6 +93,8 @@ namespace Wabbajack.Common public string Option; // -shortOption, short name of the option. Eg: -o public char ShortOption; + // text to be displayed when --help is called + public string HelpText; public CLIOptions(string option) { diff --git a/Wabbajack/App.xaml.cs b/Wabbajack/App.xaml.cs index 9672d5a6..ad59de68 100644 --- a/Wabbajack/App.xaml.cs +++ b/Wabbajack/App.xaml.cs @@ -15,6 +15,8 @@ namespace Wabbajack public App() { CLI.ParseOptions(Environment.GetCommandLineArgs()); + if(CLIArguments.Help) + CLI.DisplayHelpText(); } } } From 91cfe359a8ccc36dd9956273772b7839fdc58c14 Mon Sep 17 00:00:00 2001 From: erri120 Date: Mon, 6 Jan 2020 16:08:21 +0100 Subject: [PATCH 12/26] Created DeadlyStreamDownloader --- .../Downloaders/DeadlyStreamDownloader.cs | 24 +++++++++++++++++++ Wabbajack.Lib/Wabbajack.Lib.csproj | 1 + 2 files changed, 25 insertions(+) create mode 100644 Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs diff --git a/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs b/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs new file mode 100644 index 00000000..2da650c1 --- /dev/null +++ b/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs @@ -0,0 +1,24 @@ +using System; + +namespace Wabbajack.Lib.Downloaders +{ + public class DeadlyStreamDownloader : AbstractIPS4Downloader + { + #region INeedsDownload + public override string SiteName => "Deadly Stream"; + public override Uri SiteURL => new Uri("https://www.deadlystream.com"); + public override Uri IconUri => new Uri("https://www.deadlystream.com/favicon.ico"); + #endregion + + public DeadlyStreamDownloader() : base(new Uri("https://deadlystream.com/login"), "deadlystream", + "deadlystream.com") + { + + } + + public class State : State + { + + } + } +} diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index 44af5def..8318f13e 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -125,6 +125,7 @@ + From 837fca2580ffab89bb15e7a230cbc6b19ee0724d Mon Sep 17 00:00:00 2001 From: erri120 Date: Mon, 6 Jan 2020 16:08:54 +0100 Subject: [PATCH 13/26] Added DeadlyStream and VectorPlexus to Ceras, KnownSubTypes and Downloaders --- Wabbajack.Lib/CerasConfig.cs | 3 ++- Wabbajack.Lib/Downloaders/AbstractDownloadState.cs | 4 +++- Wabbajack.Lib/Downloaders/DownloadDispatcher.cs | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Wabbajack.Lib/CerasConfig.cs b/Wabbajack.Lib/CerasConfig.cs index 3997c8bf..7afa8d53 100644 --- a/Wabbajack.Lib/CerasConfig.cs +++ b/Wabbajack.Lib/CerasConfig.cs @@ -28,7 +28,8 @@ namespace Wabbajack.Lib typeof(BSAStateObject), typeof(BSAFileStateObject), typeof(BA2StateObject), typeof(BA2DX10EntryState), typeof(BA2FileEntryState), typeof(MediaFireDownloader.State), typeof(ArchiveMeta), typeof(PropertyFile), typeof(SteamMeta), typeof(SteamWorkshopDownloader), typeof(SteamWorkshopDownloader.State), - typeof(LoversLabDownloader.State), typeof(GameFileSourceDownloader.State) + typeof(LoversLabDownloader.State), typeof(GameFileSourceDownloader.State), typeof(VectorPlexusDownloader.State), + typeof(DeadlyStreamDownloader.State) }, }; diff --git a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs index 4ec030d8..ee9d5e49 100644 --- a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs +++ b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs @@ -21,7 +21,9 @@ namespace Wabbajack.Lib.Downloaders typeof(MegaDownloader.State), typeof(ModDBDownloader.State), typeof(NexusDownloader.State), - typeof(SteamWorkshopDownloader.State) + typeof(SteamWorkshopDownloader.State), + typeof(VectorPlexusDownloader.State), + typeof(DeadlyStreamDownloader.State) }; public static Dictionary NameToType { get; set; } public static Dictionary TypeToName { get; set; } diff --git a/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs b/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs index 9ef2f0ce..143db3d6 100644 --- a/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs +++ b/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs @@ -19,6 +19,7 @@ namespace Wabbajack.Lib.Downloaders new MediaFireDownloader(), new LoversLabDownloader(), new VectorPlexusDownloader(), + new DeadlyStreamDownloader(), new HTTPDownloader(), new ManualDownloader(), }; From 8c51c1f49e641448e23aa01a1500e428824a259b Mon Sep 17 00:00:00 2001 From: erri120 Date: Mon, 6 Jan 2020 16:20:18 +0100 Subject: [PATCH 14/26] Create portable.txt after installation in MO2 dir --- Wabbajack.Lib/MO2Compiler.cs | 3 ++- Wabbajack.Lib/MO2Installer.cs | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index f6b682dd..0c02b076 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -536,7 +536,8 @@ namespace Wabbajack.Lib new IgnoreEndsWith(this, "HavokBehaviorPostProcess.exe"), // Theme file MO2 downloads somehow new IgnoreEndsWith(this, "splash.png"), - + // File to force MO2 into portable mode + new IgnoreEndsWith(this, "portable.txt"), new IgnoreEndsWith(this, ".bin"), new IgnoreEndsWith(this, ".refcache"), diff --git a/Wabbajack.Lib/MO2Installer.cs b/Wabbajack.Lib/MO2Installer.cs index 46642daf..480f1282 100644 --- a/Wabbajack.Lib/MO2Installer.cs +++ b/Wabbajack.Lib/MO2Installer.cs @@ -44,7 +44,7 @@ namespace Wabbajack.Lib if (cancel.IsCancellationRequested) return false; var metric = Metrics.Send("begin_install", ModList.Name); - ConfigureProcessor(18, await RecommendQueueSize()); + ConfigureProcessor(19, await RecommendQueueSize()); var game = ModList.GameType.MetaData(); if (GameFolder == null) @@ -135,6 +135,9 @@ namespace Wabbajack.Lib UpdateTracker.NextStep("Generating Merges"); await zEditIntegration.GenerateMerges(this); + UpdateTracker.NextStep("Set MO2 into portable"); + ForcePortable(); + UpdateTracker.NextStep("Updating System-specific ini settings"); SetScreenSizeInPrefs(); @@ -144,6 +147,20 @@ namespace Wabbajack.Lib return true; } + private void ForcePortable() + { + var path = Path.Combine(OutputFolder, "portable.txt"); + if (File.Exists(path)) return; + + try + { + File.WriteAllText(path, "Created by Wabbajack"); + } + catch (Exception e) + { + Utils.Error(e, $"Could not create portable.txt in {OutputFolder}"); + } + } private async Task InstallIncludedDownloadMetas() { From 1eec600027a9552005cfb0d96dab2f616119e871 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 6 Jan 2020 15:00:22 -0700 Subject: [PATCH 15/26] Parse ByteArrays from INIs as UTF8 strings --- Wabbajack.Common/DynamicIniData.cs | 59 ++++++++++++++++++++++++++-- Wabbajack.Test/IniTests.cs | 27 +++++++++++++ Wabbajack.Test/Wabbajack.Test.csproj | 1 + 3 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 Wabbajack.Test/IniTests.cs diff --git a/Wabbajack.Common/DynamicIniData.cs b/Wabbajack.Common/DynamicIniData.cs index 7757f40f..594058b5 100644 --- a/Wabbajack.Common/DynamicIniData.cs +++ b/Wabbajack.Common/DynamicIniData.cs @@ -1,6 +1,11 @@ -using System.Dynamic; +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Numerics; +using System.Text; using System.Text.RegularExpressions; using IniParser; +using IniParser.Exceptions; using IniParser.Model; namespace Wabbajack.Common @@ -44,10 +49,58 @@ namespace Wabbajack.Common public override bool TryGetMember(GetMemberBinder binder, out object result) { result = _coll[binder.Name]; - if (result is string) result = Regex.Unescape(((string) result).Trim('"')); + if (result is string) result = Interpret((string)result); return true; } + private static string Interpret(string s) + { + if (s.StartsWith("@ByteArray(") && s.EndsWith(")")) + { + return UnescapeUTF8(s.Substring("@ByteArray(".Length, s.Length - "@ByteArray(".Length - ")".Length)); + } + + return UnescapeString(s); + } + + private static string UnescapeString(string s) + { + return Regex.Unescape(s.Trim('"')); + } + + private static string UnescapeUTF8(string s) + { + List acc = new List(); + for (var i = 0; i < s.Length; i++) + { + var c = s[i]; + switch (c) + { + case '\\': + i++; + var nc = s[i]; + switch (nc) + { + case '\\': + acc.Add((byte)'\\'); + break; + case 'x': + var chrs = s[i + 1] + s[i + 2].ToString(); + i += 2; + acc.Add(Convert.ToByte(chrs, 16)); + break; + default: + throw new ParsingException($"Not a valid escape characer {nc}"); + } + break; + default: + acc.Add((byte)c); + break; + } + } + return Encoding.UTF8.GetString(acc.ToArray()); + } + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { if (indexes.Length > 1) @@ -61,4 +114,4 @@ namespace Wabbajack.Common return true; } } -} \ No newline at end of file +} diff --git a/Wabbajack.Test/IniTests.cs b/Wabbajack.Test/IniTests.cs new file mode 100644 index 00000000..6ad26a1d --- /dev/null +++ b/Wabbajack.Test/IniTests.cs @@ -0,0 +1,27 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Wabbajack.Common; + +namespace Wabbajack.Test +{ + [TestClass] + public class IniTests + { + + [TestMethod] + public void TestByteArrayParsing() + { + Assert.AreEqual("bar", @"[General] + foo = bar".LoadIniString().General.foo); + + Assert.AreEqual("baz\\bar", @"[General] + foo = baz\\bar".LoadIniString().General.foo); + + Assert.AreEqual("bar", @"[General] + foo = @ByteArray(bar)".LoadIniString().General.foo); + + Assert.AreEqual("foo\\h̴̹͚̎é̶̘͙̐l̶͕̔͑p̴̯̋͂m̶̞̮͘͠e̸͉͙͆̄\\baz", @"[General] + foo = @ByteArray(foo\\\x68\xcc\xb4\xcc\x8e\xcc\xb9\xcd\x9a\x65\xcc\xb6\xcd\x81\xcc\x90\xcc\x98\xcd\x99\x6c\xcc\xb6\xcc\x94\xcd\x91\xcd\x95\x70\xcc\xb4\xcc\x8b\xcd\x82\xcc\xaf\x6d\xcc\xb6\xcd\x98\xcd\xa0\xcc\x9e\xcc\xae\x65\xcc\xb8\xcd\x86\xcc\x84\xcd\x89\xcd\x99\\baz)".LoadIniString().General.foo); + } + + } +} diff --git a/Wabbajack.Test/Wabbajack.Test.csproj b/Wabbajack.Test/Wabbajack.Test.csproj index 1b15cf8d..581ff503 100644 --- a/Wabbajack.Test/Wabbajack.Test.csproj +++ b/Wabbajack.Test/Wabbajack.Test.csproj @@ -127,6 +127,7 @@ + From b3840ae4d8c87b792a68034f0c524dd763103aef Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 6 Jan 2020 16:08:19 -0700 Subject: [PATCH 16/26] Allow .mohidden files to be patched --- Wabbajack.Lib/CompilationSteps/IncludePatches.cs | 10 ++++++++-- Wabbajack.Test/TestUtils.cs | 5 ++++- Wabbajack.Test/ZEditIntegrationTests.cs | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Wabbajack.Lib/CompilationSteps/IncludePatches.cs b/Wabbajack.Lib/CompilationSteps/IncludePatches.cs index 0677fbbf..48f86990 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludePatches.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludePatches.cs @@ -22,8 +22,14 @@ namespace Wabbajack.Lib.CompilationSteps public override async ValueTask Run(RawSourceFile source) { - if (!_indexed.TryGetValue(Path.GetFileName(source.File.Name.ToLower()), out var choices)) - return null; + var name = Path.GetFileName(source.File.Name.ToLower()); + string nameWithoutExt = name; + if (Path.GetExtension(name) == ".mohidden") + nameWithoutExt = Path.GetFileNameWithoutExtension(name); + + if (!_indexed.TryGetValue(Path.GetFileName(name), out var choices)) + if (!_indexed.TryGetValue(Path.GetFileName(nameWithoutExt), out choices)) + return null; var mod_ini = ((MO2Compiler)_compiler).ModMetas.FirstOrDefault(f => source.Path.StartsWith(f.Key)); var installationFile = mod_ini.Value?.General?.installationFile; diff --git a/Wabbajack.Test/TestUtils.cs b/Wabbajack.Test/TestUtils.cs index 0f68c4f0..b2bc22f4 100644 --- a/Wabbajack.Test/TestUtils.cs +++ b/Wabbajack.Test/TestUtils.cs @@ -185,12 +185,15 @@ namespace Wabbajack.Test public void VerifyAllFiles() { + var skip_files = new HashSet {"portable.txt"}; foreach (var dest_file in Directory.EnumerateFiles(InstallFolder, "*", DirectoryEnumerationOptions.Recursive)) { var rel_file = dest_file.RelativeTo(InstallFolder); if (rel_file.StartsWith(Consts.LOOTFolderFilesDir) || rel_file.StartsWith(Consts.GameFolderFilesDir)) continue; - Assert.IsTrue(File.Exists(Path.Combine(MO2Folder, rel_file)), $"Only in Destination: {rel_file}"); + + if (!skip_files.Contains(Path.GetExtension(rel_file))) + Assert.IsTrue(File.Exists(Path.Combine(MO2Folder, rel_file)), $"Only in Destination: {rel_file}"); } var skip_extensions = new HashSet {".txt", ".ini"}; diff --git a/Wabbajack.Test/ZEditIntegrationTests.cs b/Wabbajack.Test/ZEditIntegrationTests.cs index a4b19234..4d683aba 100644 --- a/Wabbajack.Test/ZEditIntegrationTests.cs +++ b/Wabbajack.Test/ZEditIntegrationTests.cs @@ -73,6 +73,8 @@ namespace Wabbajack.Test }); + + var modlist = await CompileAndInstall(profile); var directive = modlist.Directives.Where(m => m.To == $"mods\\{moddest}\\merged.esp").FirstOrDefault(); From afc99dce1994efe253721eb955500d04a150d6a2 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 6 Jan 2020 16:34:50 -0700 Subject: [PATCH 17/26] Bump Version --- CHANGELOG.md | 9 +++++++++ Wabbajack/Properties/AssemblyInfo.cs | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 949c39cc..6f4640d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ ### Changelog +#### Version - 1.0 beta 14 - 1/6/2020 +* Updating a list twice without starting WJ no longer deletes your modlist +* .mohidden files will now be correctly detected during binary patching +* Added support for MO2's new path format +* Added support for MO2 2.2.2's `portable.txt` feature +* Added support for VectorPlexus downloads +* Added a new CLI interface for providing Nexus API key overrides +* Several UI backend improvements + #### Version - 1.0 beta 13 - 1/4/22020 * Several fixes for steam game handling * Fixes for metrics reporting diff --git a/Wabbajack/Properties/AssemblyInfo.cs b/Wabbajack/Properties/AssemblyInfo.cs index 02512be1..7fd90515 100644 --- a/Wabbajack/Properties/AssemblyInfo.cs +++ b/Wabbajack/Properties/AssemblyInfo.cs @@ -49,5 +49,5 @@ using System.Windows; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.9.13.0")] -[assembly: AssemblyFileVersion("0.9.13.0")] +[assembly: AssemblyVersion("0.9.14.0")] +[assembly: AssemblyFileVersion("0.9.14.0")] From 873d53e76c52f1cc20a0d43e6cb20885f5853619 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 6 Jan 2020 16:44:46 -0700 Subject: [PATCH 18/26] Fix broken test --- Wabbajack.Test/TestUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wabbajack.Test/TestUtils.cs b/Wabbajack.Test/TestUtils.cs index b2bc22f4..d44b453b 100644 --- a/Wabbajack.Test/TestUtils.cs +++ b/Wabbajack.Test/TestUtils.cs @@ -192,7 +192,7 @@ namespace Wabbajack.Test if (rel_file.StartsWith(Consts.LOOTFolderFilesDir) || rel_file.StartsWith(Consts.GameFolderFilesDir)) continue; - if (!skip_files.Contains(Path.GetExtension(rel_file))) + if (!skip_files.Contains(rel_file)) Assert.IsTrue(File.Exists(Path.Combine(MO2Folder, rel_file)), $"Only in Destination: {rel_file}"); } From a76aff7962cbd3531703c547b87c86b961db3791 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 6 Jan 2020 17:24:33 -0700 Subject: [PATCH 19/26] Add override for Game Folder Files --- .../IgnoreGameFilesIfGameFolderFilesExist.cs | 46 +++++++++++++++++++ Wabbajack.Lib/MO2Compiler.cs | 1 + Wabbajack.Lib/Wabbajack.Lib.csproj | 1 + Wabbajack.Test/SanityTests.cs | 38 +++++++++++++++ Wabbajack.Test/TestUtils.cs | 29 ++++++++++++ 5 files changed, 115 insertions(+) create mode 100644 Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs b/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs new file mode 100644 index 00000000..c2dc1cdb --- /dev/null +++ b/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs @@ -0,0 +1,46 @@ +using System.Threading.Tasks; +using Alphaleonis.Win32.Filesystem; +using Wabbajack.Common; + +namespace Wabbajack.Lib.CompilationSteps +{ + public class IgnoreGameFilesIfGameFolderFilesExist : ACompilationStep + { + private readonly bool _gameFolderFilesExists; + private readonly string _gameFolder; + + public IgnoreGameFilesIfGameFolderFilesExist(ACompiler compiler) : base(compiler) + { + _gameFolderFilesExists = Directory.Exists(Path.Combine(((MO2Compiler)compiler).MO2Folder, Consts.GameFolderFilesDir)); + _gameFolder = compiler.GamePath; + } + + public override async ValueTask Run(RawSourceFile source) + { + if (_gameFolderFilesExists) + { + if (source.AbsolutePath.IsInPath(_gameFolder)) + { + var result = source.EvolveTo(); + result.Reason = $"Ignoring game files because {Consts.GameFolderFilesDir} exists"; + return result; + } + } + + return null; + } + + public override IState GetState() + { + return new State(); + } + + public class State : IState + { + public ICompilationStep CreateStep(ACompiler compiler) + { + return new IgnoreGameFilesIfGameFolderFilesExist(compiler); + } + } + } +} diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 0c02b076..679f1b20 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -496,6 +496,7 @@ namespace Wabbajack.Lib Utils.Log("Generating compilation stack"); return new List { + new IgnoreGameFilesIfGameFolderFilesExist(this), new IncludePropertyFiles(this), new IgnoreStartsWith(this,"logs\\"), new IgnoreStartsWith(this, "downloads\\"), diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index 8318f13e..d311effd 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -101,6 +101,7 @@ + diff --git a/Wabbajack.Test/SanityTests.cs b/Wabbajack.Test/SanityTests.cs index e2f9c732..053c28c6 100644 --- a/Wabbajack.Test/SanityTests.cs +++ b/Wabbajack.Test/SanityTests.cs @@ -32,6 +32,44 @@ namespace Wabbajack.Test utils.VerifyInstalledFile(mod, @"Data\scripts\test.pex"); } + + [TestMethod] + public async Task TestDirectMatchFromGameFolder() + { + + var profile = utils.AddProfile(); + var mod = utils.AddMod(); + var test_pex = utils.AddGameFile(@"enbstuff\test.pex", 10); + + utils.Configure(); + + utils.AddManualDownload( + new Dictionary {{"/baz/biz.pex", File.ReadAllBytes(test_pex)}}); + + await CompileAndInstall(profile); + + utils.VerifyInstalledGameFile(@"enbstuff\test.pex"); + } + + [TestMethod] + public async Task TestDirectMatchIsIgnoredWhenGameFolderFilesOverrideExists() + { + + var profile = utils.AddProfile(); + var mod = utils.AddMod(); + var test_pex = utils.AddGameFile(@"enbstuff\test.pex", 10); + + utils.Configure(); + + Directory.CreateDirectory(Path.Combine(utils.MO2Folder, Consts.GameFolderFilesDir)); + + utils.AddManualDownload( + new Dictionary {{"/baz/biz.pex", File.ReadAllBytes(test_pex)}}); + + await CompileAndInstall(profile); + + Assert.IsFalse(File.Exists(Path.Combine(utils.InstallFolder, Consts.GameFolderFilesDir, @"enbstuff\test.pex"))); + } [TestMethod] public async Task TestDuplicateFilesAreCopied() diff --git a/Wabbajack.Test/TestUtils.cs b/Wabbajack.Test/TestUtils.cs index d44b453b..1ad33df3 100644 --- a/Wabbajack.Test/TestUtils.cs +++ b/Wabbajack.Test/TestUtils.cs @@ -177,7 +177,26 @@ namespace Wabbajack.Test Assert.Fail($"Index {x} of {mod}\\{file} are not the same"); } } + + public void VerifyInstalledGameFile(string file) + { + var src = Path.Combine(GameFolder, file); + Assert.IsTrue(File.Exists(src), src); + var dest = Path.Combine(InstallFolder, Consts.GameFolderFilesDir, file); + Assert.IsTrue(File.Exists(dest), dest); + + var src_data = File.ReadAllBytes(src); + var dest_data = File.ReadAllBytes(dest); + + Assert.AreEqual(src_data.Length, dest_data.Length); + + for(int x = 0; x < src_data.Length; x++) + { + if (src_data[x] != dest_data[x]) + Assert.Fail($"Index {x} of {Consts.GameFolderFilesDir}\\{file} are not the same"); + } + } public string PathOfInstalledFile(string mod, string file) { return Path.Combine(InstallFolder, "mods", mod, file); @@ -218,5 +237,15 @@ namespace Wabbajack.Test } } } + + public string AddGameFile(string path, int i) + { + var full_path = Path.Combine(GameFolder, path); + var dir = Path.GetDirectoryName(full_path); + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + GenerateRandomFileData(full_path, i); + return full_path; + } } } From c50ccb964e3460411c5b9d902451b209cee0240e Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 6 Jan 2020 21:46:36 -0700 Subject: [PATCH 20/26] Don't delete the download folder --- Wabbajack.Lib/AInstaller.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index eb4de36c..3ab7058e 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -382,7 +382,10 @@ namespace Wabbajack.Lib .Do(d => indexed.Remove(d.To)); Utils.Log("Cleaning empty folders"); - var expectedFolders = indexed.Keys.SelectMany(path => + var expectedFolders = indexed.Keys + // We ignore the last part of the path, so we need a dummy file name + .Append(Path.Combine(DownloadFolder, "_")) + .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"] From 286ec75f88370c6bf6d291b8f83ca02faa452aba Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 6 Jan 2020 21:49:17 -0700 Subject: [PATCH 21/26] Version Bump --- CHANGELOG.md | 4 ++++ Wabbajack/Properties/AssemblyInfo.cs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f4640d7..d9729dd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ### Changelog +#### Version - 1.0 beta 15 - 1/6/2020 +* Don't delete the download folder when deleting empty folders during an update +* If `Game Folder Files` exists in the MO2 folder during compilation the Game folder will be ignored as a file source + #### Version - 1.0 beta 14 - 1/6/2020 * Updating a list twice without starting WJ no longer deletes your modlist * .mohidden files will now be correctly detected during binary patching diff --git a/Wabbajack/Properties/AssemblyInfo.cs b/Wabbajack/Properties/AssemblyInfo.cs index 7fd90515..5a44f29b 100644 --- a/Wabbajack/Properties/AssemblyInfo.cs +++ b/Wabbajack/Properties/AssemblyInfo.cs @@ -49,5 +49,5 @@ using System.Windows; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.9.14.0")] -[assembly: AssemblyFileVersion("0.9.14.0")] +[assembly: AssemblyVersion("0.9.15.0")] +[assembly: AssemblyFileVersion("0.9.15.0")] From 324ddae3973f8b85baecd75acac0a5304e2a6d99 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Mon, 6 Jan 2020 22:23:59 -0700 Subject: [PATCH 22/26] If game folder files exist, ignore the game folder --- Wabbajack.Lib/MO2Compiler.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 679f1b20..c3f2a80f 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -1,5 +1,6 @@ using Compression.BSA; using System; +using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; @@ -159,11 +160,21 @@ namespace Wabbajack.Lib .Where(p => p.FileExists()) .Select(p => new RawSourceFile(VFS.Index.ByRootPath[p], p.RelativeTo(MO2Folder))); - 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)))); + // If Game Folder Files exists, ignore the game folder + IEnumerable gameFiles; + if (!Directory.Exists(Path.Combine(MO2Folder, Consts.GameFolderFilesDir))) + { + 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)))); + } + else + { + gameFiles = new List(); + } + - ModMetas = Directory.EnumerateDirectories(Path.Combine(MO2Folder, "mods")) .Keep(f => { From d875fc3e5febad2932de8f5ce6b17ee4b21d08f3 Mon Sep 17 00:00:00 2001 From: erri120 Date: Tue, 7 Jan 2020 11:20:34 +0100 Subject: [PATCH 23/26] Added FNV: RU Steam ID --- Wabbajack.Common/GameMetaData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index 25646945..d30ed10c 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -178,7 +178,7 @@ namespace Wabbajack.Common MO2Name = "New Vegas", MO2ArchiveName = "falloutnv", GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\falloutnv", - SteamIDs = new List {22380}, + SteamIDs = new List {22380, 22490}, // normal and RU version RequiredFiles = new List { "FalloutNV.exe" From b0951afb80cda0b53a8dc4f780a10c1bc7862f63 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Tue, 7 Jan 2020 06:03:46 -0700 Subject: [PATCH 24/26] Moved messagebox code into user interventions, moved FilePicker VMs into Wabbajack (from Wabbajack.Lib) --- Wabbajack.Lib/MO2Installer.cs | 40 +------------------ .../CriticalFailureIntervention.cs | 27 +++++++++++++ .../StatusMessages/YesNoIntervention.cs | 15 +++++++ Wabbajack.Lib/VortexCompiler.cs | 2 +- Wabbajack.Lib/VortexInstaller.cs | 27 ++++++++----- Wabbajack.Lib/Wabbajack.Lib.csproj | 7 +--- Wabbajack.Test/FilePickerTests.cs | 1 + .../UI/FilePickerVM.cs | 2 +- {Wabbajack.Lib => Wabbajack}/UI/UIUtils.cs | 2 +- Wabbajack/View Models/Compilers/CompilerVM.cs | 1 + .../View Models/Compilers/MO2CompilerVM.cs | 1 + .../Compilers/ModlistSettingsEditorVM.cs | 1 + .../View Models/Compilers/VortexCompilerVM.cs | 1 + .../View Models/Installers/InstallerVM.cs | 7 ++-- .../View Models/Installers/MO2InstallerVM.cs | 1 + Wabbajack/View Models/ModListVM.cs | 1 + Wabbajack/View Models/ModVM.cs | 1 + Wabbajack/View Models/ModeSelectionVM.cs | 1 + .../View Models/UserInterventionHandlers.cs | 14 +++++++ Wabbajack/Views/Common/FilePicker.xaml.cs | 1 + Wabbajack/Wabbajack.csproj | 2 + 21 files changed, 94 insertions(+), 61 deletions(-) create mode 100644 Wabbajack.Lib/StatusMessages/CriticalFailureIntervention.cs create mode 100644 Wabbajack.Lib/StatusMessages/YesNoIntervention.cs rename {Wabbajack.Lib => Wabbajack}/UI/FilePickerVM.cs (99%) rename {Wabbajack.Lib => Wabbajack}/UI/UIUtils.cs (98%) diff --git a/Wabbajack.Lib/MO2Installer.cs b/Wabbajack.Lib/MO2Installer.cs index 480f1282..74a5c5b1 100644 --- a/Wabbajack.Lib/MO2Installer.cs +++ b/Wabbajack.Lib/MO2Installer.cs @@ -52,10 +52,10 @@ namespace Wabbajack.Lib if (GameFolder == null) { - MessageBox.Show( + await Utils.Log(new CriticalFailureIntervention( $"In order to do a proper install Wabbajack needs to know where your {game.MO2Name} folder resides. We tried looking the" + "game location up in the windows registry but were unable to find it, please make sure you launch the game once before running this installer. ", - "Could not find game location", MessageBoxButton.OK); + "Could not find game location")).Task; Utils.Log("Exiting because we couldn't find the game folder."); return false; } @@ -190,42 +190,6 @@ namespace Wabbajack.Lib } } - private async Task AskToEndorse() - { - var mods = ModList.Archives - .Select(m => m.State) - .OfType() - .GroupBy(f => (f.GameName, f.ModID)) - .Select(mod => mod.First()) - .ToArray(); - - var result = MessageBox.Show( - $"Installation has completed, but you have installed {mods.Length} from the Nexus, would you like to" + - " endorse these mods to show support to the authors? It will only take a few moments.", "Endorse Mods?", - MessageBoxButton.YesNo, MessageBoxImage.Question); - - if (result != MessageBoxResult.Yes) return; - - // Shuffle mods so that if we hit a API limit we don't always miss the same mods - var r = new Random(); - for (var i = 0; i < mods.Length; i++) - { - var a = r.Next(mods.Length); - var b = r.Next(mods.Length); - var tmp = mods[a]; - mods[a] = mods[b]; - mods[b] = tmp; - } - - await mods.PMap(Queue, async mod => - { - var client = await NexusApiClient.Get(); - var er = await client.EndorseMod(mod); - Utils.Log($"Endorsed {mod.GameName} - {mod.ModID} - Result: {er.message}"); - }); - Info("Done! You may now exit the application!"); - } - private async Task BuildBSAs() { var bsas = ModList.Directives.OfType().ToList(); diff --git a/Wabbajack.Lib/StatusMessages/CriticalFailureIntervention.cs b/Wabbajack.Lib/StatusMessages/CriticalFailureIntervention.cs new file mode 100644 index 00000000..2062e95a --- /dev/null +++ b/Wabbajack.Lib/StatusMessages/CriticalFailureIntervention.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Wabbajack.Common; + +namespace Wabbajack.Lib +{ + /// + /// This should probably be replaced with an error, but this is just to get messageboxes out of the .Lib library + /// + public class CriticalFailureIntervention : AUserIntervention + { + private TaskCompletionSource _source = new TaskCompletionSource(); + public Task Task => _source.Task; + + public CriticalFailureIntervention(string description, string title) + { + ExtendedDescription = description; + ShortDescription = title; + } + public override string ShortDescription { get; } + public override string ExtendedDescription { get; } + public override void Cancel() + { + Handled = true; + _source.SetResult(ConfirmationIntervention.Choice.Abort); + } + } +} diff --git a/Wabbajack.Lib/StatusMessages/YesNoIntervention.cs b/Wabbajack.Lib/StatusMessages/YesNoIntervention.cs new file mode 100644 index 00000000..b37a2be6 --- /dev/null +++ b/Wabbajack.Lib/StatusMessages/YesNoIntervention.cs @@ -0,0 +1,15 @@ +using Wabbajack.Common; + +namespace Wabbajack.Lib +{ + public class YesNoIntervention : ConfirmationIntervention + { + public YesNoIntervention(string description, string title) + { + ExtendedDescription = description; + ShortDescription = title; + } + public override string ShortDescription { get; } + public override string ExtendedDescription { get; } + } +} diff --git a/Wabbajack.Lib/VortexCompiler.cs b/Wabbajack.Lib/VortexCompiler.cs index 14957fd0..02ead8e1 100644 --- a/Wabbajack.Lib/VortexCompiler.cs +++ b/Wabbajack.Lib/VortexCompiler.cs @@ -6,8 +6,8 @@ using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Threading; -using Microsoft.WindowsAPICodePack.Shell; using Newtonsoft.Json; +using Syroot.Windows.IO; using Wabbajack.Common; using Wabbajack.Common.StoreHandlers; using Wabbajack.Lib.CompilationSteps; diff --git a/Wabbajack.Lib/VortexInstaller.cs b/Wabbajack.Lib/VortexInstaller.cs index fad6aeeb..e0062b3e 100644 --- a/Wabbajack.Lib/VortexInstaller.cs +++ b/Wabbajack.Lib/VortexInstaller.cs @@ -39,11 +39,15 @@ namespace Wabbajack.Lib { if (cancel.IsCancellationRequested) return false; var metric = Metrics.Send("begin_install", ModList.Name); - MessageBox.Show( + var result = await Utils.Log(new YesNoIntervention( "Vortex Support is still experimental and may produce unexpected results. " + "If anything fails go to the special vortex support channels on the discord. @erri120#2285 " + - "for support.", "Warning", - MessageBoxButton.OK); + "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; ConfigureProcessor(10, await RecommendQueueSize()); @@ -108,11 +112,11 @@ namespace Wabbajack.Lib if (!ModList.Directives.Any(d => d.To.StartsWith(Consts.ManualGameFilesDir))) return; - var result = MessageBox.Show("Some mods from this ModList must be installed directly into " + + 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?", "Question", MessageBoxButton.YesNo); + "to do this for you?", "Install game folder mods?")).Task; - if (result != MessageBoxResult.Yes) + if (result != ConfirmationIntervention.Choice.Continue) return; var manualFilesDir = Path.Combine(OutputFolder, Consts.ManualGameFilesDir); @@ -167,12 +171,13 @@ namespace Wabbajack.Lib if (!ModList.Directives.Any(s => s is SteamMeta)) return; - var result = MessageBox.Show("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?", - "Warning", MessageBoxButton.YesNo); + 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 != MessageBoxResult.Yes) + if (result != ConfirmationIntervention.Choice.Continue) return; await ModList.Directives.OfType() diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index d311effd..a76b1be6 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -159,8 +159,8 @@ - - + + @@ -214,9 +214,6 @@ 1.7.1 - - 1.1.3.3 - 6.0.0 diff --git a/Wabbajack.Test/FilePickerTests.cs b/Wabbajack.Test/FilePickerTests.cs index 5aff8958..33f8b16c 100644 --- a/Wabbajack.Test/FilePickerTests.cs +++ b/Wabbajack.Test/FilePickerTests.cs @@ -9,6 +9,7 @@ using DynamicData; using Microsoft.VisualStudio.TestTools.UnitTesting; using Wabbajack.Common; using Wabbajack.Lib; +using Wabbajack.UI; namespace Wabbajack.Test { diff --git a/Wabbajack.Lib/UI/FilePickerVM.cs b/Wabbajack/UI/FilePickerVM.cs similarity index 99% rename from Wabbajack.Lib/UI/FilePickerVM.cs rename to Wabbajack/UI/FilePickerVM.cs index b087fe19..9295660c 100644 --- a/Wabbajack.Lib/UI/FilePickerVM.cs +++ b/Wabbajack/UI/FilePickerVM.cs @@ -10,7 +10,7 @@ using System.Reactive.Linq; using System.Windows.Input; using Wabbajack.Lib; -namespace Wabbajack.Lib +namespace Wabbajack.UI { public class FilePickerVM : ViewModel { diff --git a/Wabbajack.Lib/UI/UIUtils.cs b/Wabbajack/UI/UIUtils.cs similarity index 98% rename from Wabbajack.Lib/UI/UIUtils.cs rename to Wabbajack/UI/UIUtils.cs index 5c0bb5c5..6c2de57c 100644 --- a/Wabbajack.Lib/UI/UIUtils.cs +++ b/Wabbajack/UI/UIUtils.cs @@ -8,7 +8,7 @@ using System.Windows.Forms; using System.Windows.Media.Imaging; using Wabbajack.Common; -namespace Wabbajack.Lib +namespace Wabbajack.UI { public static class UIUtils { diff --git a/Wabbajack/View Models/Compilers/CompilerVM.cs b/Wabbajack/View Models/Compilers/CompilerVM.cs index 5b447370..1e6f1a20 100644 --- a/Wabbajack/View Models/Compilers/CompilerVM.cs +++ b/Wabbajack/View Models/Compilers/CompilerVM.cs @@ -15,6 +15,7 @@ using System.Windows.Media.Imaging; using Wabbajack.Common; using Wabbajack.Common.StatusFeed; using Wabbajack.Lib; +using Wabbajack.UI; namespace Wabbajack { diff --git a/Wabbajack/View Models/Compilers/MO2CompilerVM.cs b/Wabbajack/View Models/Compilers/MO2CompilerVM.cs index eba68e75..a80c826c 100644 --- a/Wabbajack/View Models/Compilers/MO2CompilerVM.cs +++ b/Wabbajack/View Models/Compilers/MO2CompilerVM.cs @@ -9,6 +9,7 @@ using System.Reactive.Linq; using System.Threading.Tasks; using Wabbajack.Common; using Wabbajack.Lib; +using Wabbajack.UI; namespace Wabbajack { diff --git a/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs b/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs index 0f487134..2d94c524 100644 --- a/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs +++ b/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs @@ -6,6 +6,7 @@ using Microsoft.WindowsAPICodePack.Dialogs; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Wabbajack.Lib; +using Wabbajack.UI; namespace Wabbajack { diff --git a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs index d87ff48b..30a7567a 100644 --- a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs +++ b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs @@ -11,6 +11,7 @@ using ReactiveUI.Fody.Helpers; using Wabbajack.Common; using Wabbajack.Common.StoreHandlers; using Wabbajack.Lib; +using Wabbajack.UI; namespace Wabbajack { diff --git a/Wabbajack/View Models/Installers/InstallerVM.cs b/Wabbajack/View Models/Installers/InstallerVM.cs index 87b86e59..d27520ad 100644 --- a/Wabbajack/View Models/Installers/InstallerVM.cs +++ b/Wabbajack/View Models/Installers/InstallerVM.cs @@ -21,6 +21,7 @@ using Wabbajack.Common.StatusFeed; using System.Reactive; using System.Collections.Generic; using System.Windows.Input; +using Wabbajack.UI; namespace Wabbajack { @@ -99,12 +100,10 @@ namespace Wabbajack { if (Path.GetDirectoryName(Assembly.GetEntryAssembly().Location.ToLower()) == KnownFolders.Downloads.Path.ToLower()) { - MessageBox.Show( + Utils.Log(new CriticalFailureIntervention( "Wabbajack is running inside your Downloads folder. This folder is often highly monitored by antivirus software and these can often " + "conflict with the operations Wabbajack needs to perform. Please move this executable outside of your Downloads folder and then restart the app.", - "Cannot run inside Downloads", - MessageBoxButton.OK, - MessageBoxImage.Error); + "Cannot run inside Downloads")).Task.Wait(); Environment.Exit(1); } diff --git a/Wabbajack/View Models/Installers/MO2InstallerVM.cs b/Wabbajack/View Models/Installers/MO2InstallerVM.cs index a0909b96..b55c2537 100644 --- a/Wabbajack/View Models/Installers/MO2InstallerVM.cs +++ b/Wabbajack/View Models/Installers/MO2InstallerVM.cs @@ -11,6 +11,7 @@ using ReactiveUI; using ReactiveUI.Fody.Helpers; using Wabbajack.Common; using Wabbajack.Lib; +using Wabbajack.UI; namespace Wabbajack { diff --git a/Wabbajack/View Models/ModListVM.cs b/Wabbajack/View Models/ModListVM.cs index 264771d6..17bb3076 100644 --- a/Wabbajack/View Models/ModListVM.cs +++ b/Wabbajack/View Models/ModListVM.cs @@ -8,6 +8,7 @@ using System.Reactive.Linq; using System.Windows.Media.Imaging; using Wabbajack.Common; using Wabbajack.Lib; +using Wabbajack.UI; namespace Wabbajack { diff --git a/Wabbajack/View Models/ModVM.cs b/Wabbajack/View Models/ModVM.cs index 9b72d593..9e2344b7 100644 --- a/Wabbajack/View Models/ModVM.cs +++ b/Wabbajack/View Models/ModVM.cs @@ -8,6 +8,7 @@ using Wabbajack.Common; using Wabbajack.Lib; using Wabbajack.Lib.Downloaders; using Wabbajack.Lib.NexusApi; +using Wabbajack.UI; namespace Wabbajack { diff --git a/Wabbajack/View Models/ModeSelectionVM.cs b/Wabbajack/View Models/ModeSelectionVM.cs index 33330252..cb8b3f8f 100644 --- a/Wabbajack/View Models/ModeSelectionVM.cs +++ b/Wabbajack/View Models/ModeSelectionVM.cs @@ -6,6 +6,7 @@ using System.Reactive.Linq; using System.Windows.Input; using Wabbajack.Common; using Wabbajack.Lib; +using Wabbajack.UI; namespace Wabbajack { diff --git a/Wabbajack/View Models/UserInterventionHandlers.cs b/Wabbajack/View Models/UserInterventionHandlers.cs index 5305cb96..88c5e731 100644 --- a/Wabbajack/View Models/UserInterventionHandlers.cs +++ b/Wabbajack/View Models/UserInterventionHandlers.cs @@ -8,6 +8,7 @@ using System.Windows; using System.Windows.Threading; using ReactiveUI; using Wabbajack.Common; +using Wabbajack.Lib; using Wabbajack.Lib.Downloaders; using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.WebAutomation; @@ -73,6 +74,19 @@ namespace Wabbajack c.Resume(data); }); break; + case YesNoIntervention c: + var result = MessageBox.Show(c.ExtendedDescription, c.ShortDescription, MessageBoxButton.YesNo, + MessageBoxImage.Question); + if (result == MessageBoxResult.Yes) + c.Confirm(); + else + c.Cancel(); + break; + case CriticalFailureIntervention c: + MessageBox.Show(c.ExtendedDescription, c.ShortDescription, MessageBoxButton.OK, + MessageBoxImage.Error); + c.Cancel(); + break; case ConfirmationIntervention c: break; default: diff --git a/Wabbajack/Views/Common/FilePicker.xaml.cs b/Wabbajack/Views/Common/FilePicker.xaml.cs index 601f9203..d1a78e34 100644 --- a/Wabbajack/Views/Common/FilePicker.xaml.cs +++ b/Wabbajack/Views/Common/FilePicker.xaml.cs @@ -2,6 +2,7 @@ using System.Windows.Controls; using System.Windows.Data; using Wabbajack.Lib; +using Wabbajack.UI; namespace Wabbajack { diff --git a/Wabbajack/Wabbajack.csproj b/Wabbajack/Wabbajack.csproj index 6a4742e7..63c5d3ac 100644 --- a/Wabbajack/Wabbajack.csproj +++ b/Wabbajack/Wabbajack.csproj @@ -172,6 +172,8 @@ MSBuild:Compile Designer + + From f2bb07a52871dc6e6859275fdfe997d132d48083 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Tue, 7 Jan 2020 06:50:11 -0700 Subject: [PATCH 25/26] Wabbajack.Lib is now .NET Standard 2.0 --- Wabbajack.CacheServer/JobQueueEndpoints.cs | 1 - Wabbajack.Common/Utils.cs | 15 + Wabbajack.Common/Wabbajack.Common.csproj | 40 +-- Wabbajack.Lib/AInstaller.cs | 8 +- .../CompilationSteps/IgnoreDisabledMods.cs | 2 +- .../Downloaders/GoogleDriveDownloader.cs | 2 +- Wabbajack.Lib/Downloaders/HTTPDownloader.cs | 3 +- Wabbajack.Lib/Downloaders/ManualDownloader.cs | 2 +- Wabbajack.Lib/Exceptions/HttpException.cs | 17 + Wabbajack.Lib/MO2Installer.cs | 9 +- .../ModListRegistry/ModListMetadata.cs | 4 +- Wabbajack.Lib/NexusApi/NexusApi.cs | 5 - Wabbajack.Lib/Properties/AssemblyInfo.cs | 35 -- Wabbajack.Lib/ReportBuilder.cs | 2 +- Wabbajack.Lib/SystemParameters.cs | 8 + Wabbajack.Lib/VortexCompiler.cs | 2 +- Wabbajack.Lib/VortexInstaller.cs | 5 +- Wabbajack.Lib/Wabbajack.Lib.csproj | 318 ++++-------------- .../WebAutomation/CefSharpWrapper.cs | 1 - Wabbajack.Test/ACompilerTest.cs | 4 +- Wabbajack.Test/AVortexCompilerTest.cs | 4 +- Wabbajack.Test/EndToEndTests.cs | 4 +- Wabbajack/Util/SystemParametersConstructor.cs | 17 + .../View Models/Installers/MO2InstallerVM.cs | 4 +- .../Installers/VortexInstallerVM.cs | 4 +- Wabbajack/Wabbajack.csproj | 3 +- 26 files changed, 186 insertions(+), 333 deletions(-) create mode 100644 Wabbajack.Lib/Exceptions/HttpException.cs delete mode 100644 Wabbajack.Lib/Properties/AssemblyInfo.cs create mode 100644 Wabbajack.Lib/SystemParameters.cs create mode 100644 Wabbajack/Util/SystemParametersConstructor.cs diff --git a/Wabbajack.CacheServer/JobQueueEndpoints.cs b/Wabbajack.CacheServer/JobQueueEndpoints.cs index 8cf23027..f68ce0cb 100644 --- a/Wabbajack.CacheServer/JobQueueEndpoints.cs +++ b/Wabbajack.CacheServer/JobQueueEndpoints.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Linq.Expressions; using System.Security.Policy; using System.Threading.Tasks; -using Windows.Media.Playback; using MongoDB.Driver; using MongoDB.Driver.Linq; using Nancy; diff --git a/Wabbajack.Common/Utils.cs b/Wabbajack.Common/Utils.cs index afa739fc..377bf7e0 100644 --- a/Wabbajack.Common/Utils.cs +++ b/Wabbajack.Common/Utils.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Data.HashFunction.xxHash; using System.Diagnostics; @@ -1122,6 +1123,20 @@ namespace Wabbajack.Common return path.ToLower().TrimEnd('\\').StartsWith(parent.ToLower().TrimEnd('\\') + "\\"); } + public static HashSet ToHashSet(this IEnumerable coll) + { + var hs = new HashSet(); + coll.Do(v => hs.Add(v)); + return hs; + } + + public static HashSet ToHashSet(this T[] coll) + { + var hs = new HashSet(); + coll.Do(v => hs.Add(v)); + return hs; + } + public class NexusErrorResponse { public int code; diff --git a/Wabbajack.Common/Wabbajack.Common.csproj b/Wabbajack.Common/Wabbajack.Common.csproj index 430458da..09fecdb0 100644 --- a/Wabbajack.Common/Wabbajack.Common.csproj +++ b/Wabbajack.Common/Wabbajack.Common.csproj @@ -5,35 +5,35 @@ AnyCPU;x64 - - - + + + - - - + + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + \ No newline at end of file diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index 3ab7058e..78dd8851 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Wabbajack.Common; @@ -27,13 +28,16 @@ namespace Wabbajack.Lib public string ModListArchive { get; private set; } public ModList ModList { get; private set; } public Dictionary HashedArchives { get; set; } + + public SystemParameters SystemParameters { get; set; } - public AInstaller(string archive, ModList modList, string outputFolder, string downloadFolder) + public AInstaller(string archive, ModList modList, string outputFolder, string downloadFolder, SystemParameters parameters) { ModList = modList; ModListArchive = archive; OutputFolder = outputFolder; DownloadFolder = downloadFolder; + SystemParameters = parameters; } public void Info(string msg) @@ -108,7 +112,7 @@ namespace Wabbajack.Lib Info("Building Folder Structure"); ModList.Directives .Select(d => Path.Combine(OutputFolder, Path.GetDirectoryName(d.To))) - .ToHashSet() + .Distinct() .Do(f => { if (Directory.Exists(f)) return; diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs b/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs index 4f28c933..c39240af 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs @@ -15,7 +15,7 @@ namespace Wabbajack.Lib.CompilationSteps public IgnoreDisabledMods(ACompiler compiler) : base(compiler) { _mo2Compiler = (MO2Compiler) compiler; - var alwaysEnabled = _mo2Compiler.ModInis.Where(f => IsAlwaysEnabled(f.Value)).Select(f => f.Key).ToHashSet(); + var alwaysEnabled = _mo2Compiler.ModInis.Where(f => IsAlwaysEnabled(f.Value)).Select(f => f.Key).Distinct(); _allEnabledMods = _mo2Compiler.SelectedProfiles .SelectMany(p => File.ReadAllLines(Path.Combine(_mo2Compiler.MO2Folder, "profiles", p, "modlist.txt"))) diff --git a/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs b/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs index 32bc3488..385f7212 100644 --- a/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs @@ -1,8 +1,8 @@ using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Web; using Wabbajack.Common; +using Wabbajack.Lib.Exceptions; using Wabbajack.Lib.Validation; namespace Wabbajack.Lib.Downloaders diff --git a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs index dd353f9b..c9264885 100644 --- a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs +++ b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs @@ -7,11 +7,10 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Reflection.Emit; using System.Threading.Tasks; -using System.Web; -using Windows.Networking.BackgroundTransfer; using Ceras; using SharpCompress.Common; using Wabbajack.Common; +using Wabbajack.Lib.Exceptions; using Wabbajack.Lib.Validation; using File = Alphaleonis.Win32.Filesystem.File; diff --git a/Wabbajack.Lib/Downloaders/ManualDownloader.cs b/Wabbajack.Lib/Downloaders/ManualDownloader.cs index c3352514..988dad42 100644 --- a/Wabbajack.Lib/Downloaders/ManualDownloader.cs +++ b/Wabbajack.Lib/Downloaders/ManualDownloader.cs @@ -5,8 +5,8 @@ using System.Linq; using System.Reactive.Linq; using System.Reactive.Subjects; using System.Threading.Tasks; -using Syroot.Windows.IO; using Wabbajack.Common; +using Wabbajack.Common.IO; using Wabbajack.Lib.Validation; using File = System.IO.File; diff --git a/Wabbajack.Lib/Exceptions/HttpException.cs b/Wabbajack.Lib/Exceptions/HttpException.cs new file mode 100644 index 00000000..41d46b03 --- /dev/null +++ b/Wabbajack.Lib/Exceptions/HttpException.cs @@ -0,0 +1,17 @@ +using System; + +namespace Wabbajack.Lib.Exceptions +{ + public class HttpException : Exception + { + public string Reason { get; set; } + public int Code { get; set; } + + public HttpException(int code, string reason) : base($"Http Error {code} - {reason}") + { + Code = code; + Reason = reason; + } + + } +} diff --git a/Wabbajack.Lib/MO2Installer.cs b/Wabbajack.Lib/MO2Installer.cs index 74a5c5b1..8827739f 100644 --- a/Wabbajack.Lib/MO2Installer.cs +++ b/Wabbajack.Lib/MO2Installer.cs @@ -30,12 +30,13 @@ namespace Wabbajack.Lib public string GameFolder { get; set; } - public MO2Installer(string archive, ModList modList, string outputFolder, string downloadFolder) + public MO2Installer(string archive, ModList modList, string outputFolder, string downloadFolder, SystemParameters parameters) : base( archive: archive, modList: modList, outputFolder: outputFolder, - downloadFolder: downloadFolder) + downloadFolder: downloadFolder, + parameters: parameters) { } @@ -280,8 +281,8 @@ namespace Wabbajack.Lib if (data.Sections["Display"]["iSize W"] != null && data.Sections["Display"]["iSize H"] != null) { - data.Sections["Display"]["iSize W"] = SystemParameters.PrimaryScreenWidth.ToString(CultureInfo.CurrentCulture); - data.Sections["Display"]["iSize H"] = SystemParameters.PrimaryScreenHeight.ToString(CultureInfo.CurrentCulture); + data.Sections["Display"]["iSize W"] = SystemParameters.ScreenWidth.ToString(CultureInfo.CurrentCulture); + data.Sections["Display"]["iSize H"] = SystemParameters.ScreenHeight.ToString(CultureInfo.CurrentCulture); } parser.WriteFile(file, data); diff --git a/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs b/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs index c42f54c8..038777a8 100644 --- a/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs +++ b/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using System.Net.Http; using System.Threading.Tasks; -using System.Windows.Media.Imaging; using Newtonsoft.Json; using Wabbajack.Common; using File = System.IO.File; @@ -45,7 +45,7 @@ namespace Wabbajack.Lib.ModListRegistry public string ImageUri { get; set; } [JsonIgnore] - public BitmapImage Image { get; set; } + public Bitmap Image { get; set; } [JsonProperty("readme")] public string Readme { get; set; } diff --git a/Wabbajack.Lib/NexusApi/NexusApi.cs b/Wabbajack.Lib/NexusApi/NexusApi.cs index 4365a6c3..c4e417bb 100644 --- a/Wabbajack.Lib/NexusApi/NexusApi.cs +++ b/Wabbajack.Lib/NexusApi/NexusApi.cs @@ -8,17 +8,12 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Reflection; using System.Security.Authentication; -using System.Text; using System.Threading.Tasks; using Wabbajack.Common; using Wabbajack.Lib.Downloaders; -using Wabbajack.Lib.LibCefHelpers; using WebSocketSharp; using static Wabbajack.Lib.NexusApi.NexusApiUtils; using System.Threading; -using CefSharp; -using CefSharp.Handler; -using Newtonsoft.Json; using Wabbajack.Lib.WebAutomation; namespace Wabbajack.Lib.NexusApi diff --git a/Wabbajack.Lib/Properties/AssemblyInfo.cs b/Wabbajack.Lib/Properties/AssemblyInfo.cs deleted file mode 100644 index 5d41ef04..00000000 --- a/Wabbajack.Lib/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Wabbajack.Lib")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Wabbajack.Lib")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("0a820830-a298-497d-85e0-e9a89efef5fe")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Wabbajack.Lib/ReportBuilder.cs b/Wabbajack.Lib/ReportBuilder.cs index 8096a162..8c64570d 100644 --- a/Wabbajack.Lib/ReportBuilder.cs +++ b/Wabbajack.Lib/ReportBuilder.cs @@ -129,7 +129,7 @@ namespace Wabbajack.Lib .Concat(lst.Directives .OfType() .Select(f => (f.To, "patched", SizeForID(f.PatchID)))) - .ToHashSet() + .Distinct() .OrderByDescending(f => f.Item3); NoWrapText("\n\n### Summary of inlined files in this installer"); diff --git a/Wabbajack.Lib/SystemParameters.cs b/Wabbajack.Lib/SystemParameters.cs new file mode 100644 index 00000000..ceec3d09 --- /dev/null +++ b/Wabbajack.Lib/SystemParameters.cs @@ -0,0 +1,8 @@ +namespace Wabbajack.Lib +{ + public class SystemParameters + { + public int ScreenHeight { get; set; } + public int ScreenWidth { get; set; } + } +} diff --git a/Wabbajack.Lib/VortexCompiler.cs b/Wabbajack.Lib/VortexCompiler.cs index 02ead8e1..adb0bb49 100644 --- a/Wabbajack.Lib/VortexCompiler.cs +++ b/Wabbajack.Lib/VortexCompiler.cs @@ -7,8 +7,8 @@ using System.Text; using System.Threading.Tasks; using System.Threading; using Newtonsoft.Json; -using Syroot.Windows.IO; using Wabbajack.Common; +using Wabbajack.Common.IO; using Wabbajack.Common.StoreHandlers; using Wabbajack.Lib.CompilationSteps; using Wabbajack.Lib.NexusApi; diff --git a/Wabbajack.Lib/VortexInstaller.cs b/Wabbajack.Lib/VortexInstaller.cs index e0062b3e..2d86df47 100644 --- a/Wabbajack.Lib/VortexInstaller.cs +++ b/Wabbajack.Lib/VortexInstaller.cs @@ -20,12 +20,13 @@ namespace Wabbajack.Lib public override ModManager ModManager => ModManager.Vortex; - public VortexInstaller(string archive, ModList modList, string outputFolder, string downloadFolder) + public VortexInstaller(string archive, ModList modList, string outputFolder, string downloadFolder, SystemParameters parameters) : base( archive: archive, modList: modList, outputFolder: outputFolder, - downloadFolder: downloadFolder) + downloadFolder: downloadFolder, + parameters: parameters) { #if DEBUG // TODO: only for testing diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index a76b1be6..bbc886c9 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -1,250 +1,72 @@  - - - - Debug - AnyCPU - {0A820830-A298-497D-85E0-E9A89EFEF5FE} - Library - Properties - Wabbajack.Lib - Wabbajack.Lib - v4.8 - 512 - true - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - x64 - CS1998 - CS4014 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - CS1998 - CS4014 - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - false - CS4014 - CS1998 - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - CS4014 - CS1998 - - - - ..\..\..\Users\tbald\.nuget\packages\mongodb.bson\2.10.0\lib\net452\MongoDB.Bson.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {ff5d892f-8ff4-44fc-8f7f-cd58f307ad1b} - Compression.BSA - - - {b3f3fb6e-b9eb-4f49-9875-d78578bc7ae5} - Wabbajack.Common - - - {5D6A2EAF-6604-4C51-8AE2-A746B4BC5E3E} - Wabbajack.VirtualFileSystem - - - - - - - - - - - 2.2.6 - - - 75.1.143 - - - 4.1.7 - - - 0.15.1 - - - 1.11.17 - - - 1.7.1 - - - 6.0.0 - - - 2.1.0 - - - 12.0.3 - - - 11.1.1 - - - 11.1.1 - - - 0.24.0 - - - 1.2.1 - - - 4.3.2 - - - 1.0.4 - - - 8.0.0 - - - - + + + netstandard2.0 + AnyCPU;x64 + + + + 75.1.143 + + + 75.1.143 + + + 4.1.7 + + + 0.15.1 + + + 6.0.6 + + + 2.2.2.1 + + + 1.11.17 + + + 1.7.1 + + + 4.7.0 + + + 2.1.0 + + + 11.1.6 + + + 11.1.6 + + + 0.24.0 + + + 1.7.0 + + + 4.7.0 + + + 4.3.4 + + + 1.0.1 + + + 1.0.0 + + + + + + + + + + + \ No newline at end of file diff --git a/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs b/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs index 84fa7c37..fcb9e919 100644 --- a/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs +++ b/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.Remoting.Channels; using System.Text; using System.Threading.Tasks; using CefSharp; diff --git a/Wabbajack.Test/ACompilerTest.cs b/Wabbajack.Test/ACompilerTest.cs index 58f2d5cd..19b8fd07 100644 --- a/Wabbajack.Test/ACompilerTest.cs +++ b/Wabbajack.Test/ACompilerTest.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Wabbajack.Common; using Wabbajack.Lib; using Wabbajack.Lib.LibCefHelpers; +using Wabbajack.Util; namespace Wabbajack.Test { @@ -57,7 +58,8 @@ namespace Wabbajack.Test archive: compiler.ModListOutputFile, modList: modlist, outputFolder: utils.InstallFolder, - downloadFolder: utils.DownloadsFolder); + downloadFolder: utils.DownloadsFolder, + parameters: SystemParametersConstructor.Create()); installer.WarnOnOverwrite = false; installer.GameFolder = utils.GameFolder; await installer.Begin(); diff --git a/Wabbajack.Test/AVortexCompilerTest.cs b/Wabbajack.Test/AVortexCompilerTest.cs index 1f9c7466..a8691415 100644 --- a/Wabbajack.Test/AVortexCompilerTest.cs +++ b/Wabbajack.Test/AVortexCompilerTest.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Wabbajack.Common; using Wabbajack.Lib; +using Wabbajack.Util; namespace Wabbajack.Test { @@ -67,7 +68,8 @@ namespace Wabbajack.Test archive: vortexCompiler.ModListOutputFile, modList: modList, outputFolder: utils.InstallFolder, - downloadFolder: utils.DownloadsFolder) + downloadFolder: utils.DownloadsFolder, + parameters: SystemParametersConstructor.Create()) { GameFolder = utils.GameFolder, }; diff --git a/Wabbajack.Test/EndToEndTests.cs b/Wabbajack.Test/EndToEndTests.cs index d120ede9..1a9da3ef 100644 --- a/Wabbajack.Test/EndToEndTests.cs +++ b/Wabbajack.Test/EndToEndTests.cs @@ -8,6 +8,7 @@ using Wabbajack.Common; using Wabbajack.Lib; using Wabbajack.Lib.Downloaders; using Wabbajack.Lib.NexusApi; +using Wabbajack.Util; namespace Wabbajack.Test { @@ -153,7 +154,8 @@ namespace Wabbajack.Test archive: compiler.ModListOutputFile, modList: modlist, outputFolder: utils.InstallFolder, - downloadFolder: utils.DownloadsFolder); + downloadFolder: utils.DownloadsFolder, + parameters: SystemParametersConstructor.Create()); installer.GameFolder = utils.GameFolder; await installer.Begin(); } diff --git a/Wabbajack/Util/SystemParametersConstructor.cs b/Wabbajack/Util/SystemParametersConstructor.cs new file mode 100644 index 00000000..e8b3ddbc --- /dev/null +++ b/Wabbajack/Util/SystemParametersConstructor.cs @@ -0,0 +1,17 @@ +using MahApps.Metro.Controls; +using Wabbajack.Lib; + +namespace Wabbajack.Util +{ + public static class SystemParametersConstructor + { + public static SystemParameters Create() + { + return new SystemParameters + { + ScreenWidth = (int)System.Windows.SystemParameters.PrimaryScreenWidth, + ScreenHeight = (int)System.Windows.SystemParameters.PrimaryScreenHeight + }; + } + } +} diff --git a/Wabbajack/View Models/Installers/MO2InstallerVM.cs b/Wabbajack/View Models/Installers/MO2InstallerVM.cs index b55c2537..f32b5a1d 100644 --- a/Wabbajack/View Models/Installers/MO2InstallerVM.cs +++ b/Wabbajack/View Models/Installers/MO2InstallerVM.cs @@ -12,6 +12,7 @@ using ReactiveUI.Fody.Helpers; using Wabbajack.Common; using Wabbajack.Lib; using Wabbajack.UI; +using Wabbajack.Util; namespace Wabbajack { @@ -149,7 +150,8 @@ namespace Wabbajack archive: Parent.ModListLocation.TargetPath, modList: Parent.ModList.SourceModList, outputFolder: Location.TargetPath, - downloadFolder: DownloadLocation.TargetPath); + downloadFolder: DownloadLocation.TargetPath, + parameters: SystemParametersConstructor.Create()); await Task.Run(async () => { diff --git a/Wabbajack/View Models/Installers/VortexInstallerVM.cs b/Wabbajack/View Models/Installers/VortexInstallerVM.cs index efc91e02..6952ee86 100644 --- a/Wabbajack/View Models/Installers/VortexInstallerVM.cs +++ b/Wabbajack/View Models/Installers/VortexInstallerVM.cs @@ -8,6 +8,7 @@ using ReactiveUI; using ReactiveUI.Fody.Helpers; using Wabbajack.Common; using Wabbajack.Lib; +using Wabbajack.Util; namespace Wabbajack { @@ -66,7 +67,8 @@ namespace Wabbajack archive: Parent.ModListLocation.TargetPath, modList: Parent.ModList.SourceModList, outputFolder: staging, - downloadFolder: download); + downloadFolder: download, + parameters: SystemParametersConstructor.Create()); await Task.Run(async () => { diff --git a/Wabbajack/Wabbajack.csproj b/Wabbajack/Wabbajack.csproj index 63c5d3ac..e676468a 100644 --- a/Wabbajack/Wabbajack.csproj +++ b/Wabbajack/Wabbajack.csproj @@ -174,6 +174,7 @@ + @@ -536,7 +537,7 @@ 11.1.1 - 11.1.1 + 11.1.6 11.1.1 From 8e23dbe972f0d070ea1a1780982f89402773bab4 Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Tue, 7 Jan 2020 07:20:36 -0700 Subject: [PATCH 26/26] Embed css files --- Wabbajack.Lib/Wabbajack.Lib.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index bbc886c9..57b0cf35 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -68,5 +68,7 @@ + + \ No newline at end of file