From 3b0e10c86d921fd15731580f4c05e84280ccde47 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 12:12:33 -0500 Subject: [PATCH 01/23] Nullability fix. Removed unused json parameters --- Wabbajack.Common/Json.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Wabbajack.Common/Json.cs b/Wabbajack.Common/Json.cs index 4d2584c7..0ea17952 100644 --- a/Wabbajack.Common/Json.cs +++ b/Wabbajack.Common/Json.cs @@ -59,16 +59,12 @@ namespace Wabbajack.Common return JsonConvert.SerializeObject(obj, JsonSettings); } - public static T FromJson(this AbsolutePath filename, - TypeNameHandling handling = TypeNameHandling.All, - TypeNameAssemblyFormatHandling format = TypeNameAssemblyFormatHandling.Full) + public static T FromJson(this AbsolutePath filename) { return JsonConvert.DeserializeObject(filename.ReadAllText(), JsonSettings)!; } - public static T FromJsonString(this string data, - TypeNameHandling handling = TypeNameHandling.Objects, - TypeNameAssemblyFormatHandling format = TypeNameAssemblyFormatHandling.Full) + public static T FromJsonString(this string data) { return JsonConvert.DeserializeObject(data, JsonSettings)!; } @@ -78,10 +74,8 @@ namespace Wabbajack.Common using var tr = new StreamReader(stream, Encoding.UTF8, leaveOpen: true); using var reader = new JsonTextReader(tr); var ser = JsonSerializer.Create(JsonSettings); - return ser.Deserialize(reader); + return ser.Deserialize(reader)!; } - - private class HashJsonConverter : JsonConverter { From 5377cd0cce3102d4d7e35ff2d2285bdbbc4d7ca0 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sat, 4 Apr 2020 13:25:52 -0500 Subject: [PATCH 02/23] WorkQueue's active threads observable nullable as intended again --- Wabbajack.Common/WorkQueue.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Wabbajack.Common/WorkQueue.cs b/Wabbajack.Common/WorkQueue.cs index ceab2e05..d9667669 100644 --- a/Wabbajack.Common/WorkQueue.cs +++ b/Wabbajack.Common/WorkQueue.cs @@ -49,7 +49,7 @@ namespace Wabbajack.Common private readonly BehaviorSubject<(int DesiredCPUs, int CurrentCPUs)> _cpuCountSubj = new BehaviorSubject<(int DesiredCPUs, int CurrentCPUs)>((0, 0)); public IObservable<(int CurrentCPUs, int DesiredCPUs)> CurrentCpuCount => _cpuCountSubj; - private readonly Subject> _activeNumThreadsObservable = new Subject>(); + private readonly Subject?> _activeNumThreadsObservable = new Subject?>(); public static TimeSpan PollMS = TimeSpan.FromMilliseconds(200); @@ -66,7 +66,7 @@ namespace Wabbajack.Common /// Creates a WorkQueue whos number of threads is determined by the given observable /// /// Driving observable that determines how many threads should be actively pulling jobs from the queue - public WorkQueue(IObservable numThreads) + public WorkQueue(IObservable? numThreads) { // Hook onto the number of active threads subject, and subscribe to it for changes _activeNumThreadsObservable @@ -86,7 +86,7 @@ namespace Wabbajack.Common /// Sets the driving observable that determines how many threads should be actively pulling jobs from the queue /// /// Driving observable that determines how many threads should be actively pulling jobs from the queue - public void SetActiveThreadsObservable(IObservable numThreads) + public void SetActiveThreadsObservable(IObservable? numThreads) { _activeNumThreadsObservable.OnNext(numThreads); } From 6572f14f49cf9ca79b2da6a3d390dce46cff88ff Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sat, 4 Apr 2020 13:26:14 -0500 Subject: [PATCH 03/23] ABatchProcessor nullable. ConfigureProcessor removed --- Wabbajack.Lib/ABatchProcessor.cs | 15 +++++---------- Wabbajack.Lib/ACompiler.cs | 7 ++++++- Wabbajack.Lib/AInstaller.cs | 3 ++- Wabbajack.Lib/IBatchProcessor.cs | 1 + Wabbajack.Lib/MO2Compiler.cs | 3 ++- Wabbajack.Lib/MO2Installer.cs | 5 +++-- Wabbajack.Lib/VortexInstaller.cs | 5 +++-- Wabbajack.Test/DownloaderTests.cs | 13 +++---------- Wabbajack/Converters/BoolToVisibilityConverter.cs | 2 +- 9 files changed, 26 insertions(+), 28 deletions(-) diff --git a/Wabbajack.Lib/ABatchProcessor.cs b/Wabbajack.Lib/ABatchProcessor.cs index af0ecf46..ef775efc 100644 --- a/Wabbajack.Lib/ABatchProcessor.cs +++ b/Wabbajack.Lib/ABatchProcessor.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Wabbajack.Common; using Wabbajack.Common.StatusFeed; using Wabbajack.VirtualFileSystem; +#nullable enable namespace Wabbajack.Lib { @@ -15,9 +16,9 @@ namespace Wabbajack.Lib { public WorkQueue Queue { get; } = new WorkQueue(); - public Context VFS { get; private set; } + public Context VFS { get; } - protected StatusUpdateTracker UpdateTracker { get; private set; } + protected StatusUpdateTracker UpdateTracker { get; } private Subject _percentCompleted { get; } = new Subject(); @@ -42,7 +43,6 @@ namespace Wabbajack.Lib private Subject _isRunning { get; } = new Subject(); public IObservable IsRunning => _isRunning; - private int _configured; private int _started; private readonly CancellationTokenSource _cancel = new CancellationTokenSource(); @@ -53,21 +53,16 @@ namespace Wabbajack.Lib public BehaviorSubject MaxCores = new BehaviorSubject(byte.MaxValue); public BehaviorSubject TargetUsagePercent = new BehaviorSubject(Percent.One); - protected void ConfigureProcessor(int steps, IObservable numThreads = null) + public ABatchProcessor(int steps) { - if (1 == Interlocked.CompareExchange(ref _configured, 1, 1)) - { - throw new InvalidDataException("Can't configure a processor twice"); - } - Queue.SetActiveThreadsObservable(numThreads); UpdateTracker = new StatusUpdateTracker(steps); + VFS = new Context(Queue) { UpdateTracker = UpdateTracker }; Queue.Status.Subscribe(_queueStatus) .DisposeWith(_subs); Queue.LogMessages.Subscribe(_logMessages) .DisposeWith(_subs); UpdateTracker.Progress.Subscribe(_percentCompleted); UpdateTracker.StepName.Subscribe(_textStatus); - VFS = new Context(Queue) { UpdateTracker = UpdateTracker }; } /// diff --git a/Wabbajack.Lib/ACompiler.cs b/Wabbajack.Lib/ACompiler.cs index e368db17..ba162ca2 100644 --- a/Wabbajack.Lib/ACompiler.cs +++ b/Wabbajack.Lib/ACompiler.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; @@ -50,6 +50,11 @@ namespace Wabbajack.Lib public List IndexedArchives = new List(); public Dictionary> IndexedFiles = new Dictionary>(); + public ACompiler(int steps) + : base(steps) + { + } + public static void Info(string msg) { Utils.Log(msg); diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index 497ffd33..43719b81 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -31,7 +31,8 @@ namespace Wabbajack.Lib public SystemParameters SystemParameters { get; set; } - public AInstaller(AbsolutePath archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters) + public AInstaller(AbsolutePath archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters, int steps) + : base(steps) { ModList = modList; ModListArchive = archive; diff --git a/Wabbajack.Lib/IBatchProcessor.cs b/Wabbajack.Lib/IBatchProcessor.cs index ebf4531f..e8f34b8c 100644 --- a/Wabbajack.Lib/IBatchProcessor.cs +++ b/Wabbajack.Lib/IBatchProcessor.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 4ddc87ca..1f9ea5a1 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -49,6 +49,7 @@ namespace Wabbajack.Lib $"vfs_compile_cache-{Path.Combine((string)MO2Folder ?? "Unknown", "ModOrganizer.exe").StringSha256Hex()}.bin"); public MO2Compiler(AbsolutePath mo2Folder, string mo2Profile, AbsolutePath outputFile) + : base(steps: 20) { MO2Folder = mo2Folder; MO2Profile = mo2Profile; @@ -88,7 +89,7 @@ namespace Wabbajack.Lib protected override async Task _Begin(CancellationToken cancel) { if (cancel.IsCancellationRequested) return false; - ConfigureProcessor(20, ConstructDynamicNumThreads(await RecommendQueueSize())); + Queue.SetActiveThreadsObservable(ConstructDynamicNumThreads(await RecommendQueueSize())); UpdateTracker.Reset(); UpdateTracker.NextStep("Gathering information"); Info("Looking for other profiles"); diff --git a/Wabbajack.Lib/MO2Installer.cs b/Wabbajack.Lib/MO2Installer.cs index a1fa887a..050ab03a 100644 --- a/Wabbajack.Lib/MO2Installer.cs +++ b/Wabbajack.Lib/MO2Installer.cs @@ -38,7 +38,8 @@ namespace Wabbajack.Lib modList: modList, outputFolder: outputFolder, downloadFolder: downloadFolder, - parameters: parameters) + parameters: parameters, + steps: 20) { } @@ -48,7 +49,7 @@ namespace Wabbajack.Lib var metric = Metrics.Send(Metrics.BeginInstall, ModList.Name); Utils.Log("Configuring Processor"); - ConfigureProcessor(20, ConstructDynamicNumThreads(await RecommendQueueSize())); + Queue.SetActiveThreadsObservable(ConstructDynamicNumThreads(await RecommendQueueSize())); var game = ModList.GameType.MetaData(); if (GameFolder == null) diff --git a/Wabbajack.Lib/VortexInstaller.cs b/Wabbajack.Lib/VortexInstaller.cs index 72ee01c4..78ba8d1e 100644 --- a/Wabbajack.Lib/VortexInstaller.cs +++ b/Wabbajack.Lib/VortexInstaller.cs @@ -26,7 +26,8 @@ namespace Wabbajack.Lib modList: modList, outputFolder: outputFolder, downloadFolder: downloadFolder, - parameters: parameters) + parameters: parameters, + steps: 10) { #if DEBUG // TODO: only for testing @@ -51,7 +52,7 @@ namespace Wabbajack.Lib } if (cancel.IsCancellationRequested) return false; - ConfigureProcessor(10, ConstructDynamicNumThreads(await RecommendQueueSize())); + Queue.SetActiveThreadsObservable(ConstructDynamicNumThreads(await RecommendQueueSize())); DownloadFolder.CreateDirectory(); if (cancel.IsCancellationRequested) return false; diff --git a/Wabbajack.Test/DownloaderTests.cs b/Wabbajack.Test/DownloaderTests.cs index f3c6c4d1..e1d52437 100644 --- a/Wabbajack.Test/DownloaderTests.cs +++ b/Wabbajack.Test/DownloaderTests.cs @@ -532,7 +532,6 @@ namespace Wabbajack.Test return state.ToJson().FromJsonString(); } - [Fact] public async Task TestUpgrading() { @@ -553,13 +552,12 @@ namespace Wabbajack.Test Assert.Equal(Hash.FromBase64("gCRVrvzDNH0="), await dest.FileHashCachedAsync()); } - - class TestInstaller : AInstaller { - public TestInstaller(AbsolutePath archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters) : base(archive, modList, outputFolder, downloadFolder, parameters) + public TestInstaller(AbsolutePath archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters) + : base(archive, modList, outputFolder, downloadFolder, parameters, steps: 1) { - ConfigureProcessor(1, new Subject().StartWith(1)); + Queue.SetActiveThreadsObservable(Observable.Return(1)); } protected override Task _Begin(CancellationToken cancel) @@ -569,10 +567,5 @@ namespace Wabbajack.Test public override ModManager ModManager { get => ModManager.MO2; } } - - } - - - } diff --git a/Wabbajack/Converters/BoolToVisibilityConverter.cs b/Wabbajack/Converters/BoolToVisibilityConverter.cs index 8a132dd8..8e577fdd 100644 --- a/Wabbajack/Converters/BoolToVisibilityConverter.cs +++ b/Wabbajack/Converters/BoolToVisibilityConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using System.Windows; using System.Windows.Data; From 64f5531411bbf911f18878eae9511a902c19b77b Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 12:17:24 -0500 Subject: [PATCH 04/23] Wabbajack.Lib: Some nullability enabled --- Wabbajack.Lib/ACompiler.cs | 8 +++--- Wabbajack.Lib/AInstaller.cs | 16 ++++++++---- Wabbajack.Lib/ClientAPI.cs | 5 ++-- Wabbajack.Lib/MO2Installer.cs | 26 ++++++++++--------- Wabbajack.Lib/Manifest.cs | 1 + Wabbajack.Lib/SystemParameters.cs | 7 ++--- Wabbajack.Lib/ViewModel.cs | 3 ++- Wabbajack.Lib/VortexCompiler.cs | 1 + Wabbajack.Lib/VortexInstaller.cs | 1 + Wabbajack.Lib/zEditIntegration.cs | 1 + Wabbajack/Util/SystemParametersConstructor.cs | 1 - 11 files changed, 42 insertions(+), 28 deletions(-) diff --git a/Wabbajack.Lib/ACompiler.cs b/Wabbajack.Lib/ACompiler.cs index ba162ca2..aa036ddd 100644 --- a/Wabbajack.Lib/ACompiler.cs +++ b/Wabbajack.Lib/ACompiler.cs @@ -14,15 +14,16 @@ using Wabbajack.VirtualFileSystem; using Directory = Alphaleonis.Win32.Filesystem.Directory; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; +#nullable enable namespace Wabbajack.Lib { public abstract class ACompiler : ABatchProcessor { - public string ModListName, ModListAuthor, ModListDescription, ModListWebsite; + public string? ModListName, ModListAuthor, ModListDescription, ModListWebsite; public AbsolutePath ModListImage, ModListReadme; public bool ReadmeIsWebsite; - protected Version WabbajackVersion; + protected Version? WabbajackVersion; public abstract AbsolutePath VFSCacheName { get; } //protected string VFSCacheName => Path.Combine(Consts.LocalAppDataPath, $"vfs_compile_cache.bin"); @@ -231,8 +232,7 @@ namespace Wabbajack.Lib return await ResolveArchive(found); } - Error($"No match found for Archive sha: {hash.ToBase64()} this shouldn't happen"); - return null; + throw new ArgumentException($"No match found for Archive sha: {hash.ToBase64()} this shouldn't happen"); } public async Task ResolveArchive(IndexedArchive archive) diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index 43719b81..ac103756 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -13,6 +13,7 @@ using Directory = Alphaleonis.Win32.Filesystem.Directory; using File = Alphaleonis.Win32.Filesystem.File; using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; using Path = Alphaleonis.Win32.Filesystem.Path; +#nullable enable namespace Wabbajack.Lib { @@ -27,7 +28,7 @@ namespace Wabbajack.Lib public AbsolutePath ModListArchive { get; private set; } public ModList ModList { get; private set; } - public Dictionary HashedArchives { get; set; } + public Dictionary HashedArchives { get; } = new Dictionary(); public SystemParameters SystemParameters { get; set; } @@ -279,11 +280,11 @@ namespace Wabbajack.Lib var hashResults = await DownloadFolder.EnumerateFiles() .Where(e => e.Extension != Consts.HashFileExtension) .PMap(Queue, async e => (await e.FileHashCachedAsync(), e)); - HashedArchives = hashResults + HashedArchives.Add(hashResults .OrderByDescending(e => e.Item2.LastModified) .GroupBy(e => e.Item1) .Select(e => e.First()) - .ToDictionary(e => e.Item1, e => e.Item2); + .Select(e => new KeyValuePair(e.Item1, e.Item2))); } /// @@ -392,8 +393,13 @@ namespace Wabbajack.Lib return await path.FileHashAsync() == d.Hash ? d : null; })) - .Where(d => d != null) - .Do(d => indexed.Remove(d.To)); + .Do(d => + { + if (d != null) + { + indexed.Remove(d.To); + } + }); UpdateTracker.NextStep("Updating ModList"); Utils.Log($"Optimized {ModList.Directives.Count} directives to {indexed.Count} required"); diff --git a/Wabbajack.Lib/ClientAPI.cs b/Wabbajack.Lib/ClientAPI.cs index c750782b..80fc2043 100644 --- a/Wabbajack.Lib/ClientAPI.cs +++ b/Wabbajack.Lib/ClientAPI.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Wabbajack.Common; using Wabbajack.Lib.Exceptions; +#nullable enable namespace Wabbajack.Lib { @@ -14,7 +15,7 @@ namespace Wabbajack.Lib return client; } - public static async Task GetModUpgrade(Hash hash) + public static async Task GetModUpgrade(Hash hash) { using var response = await GetClient() .GetAsync($"{Consts.WabbajackBuildServerUri}alternative/{hash.ToHex()}"); @@ -33,7 +34,7 @@ namespace Wabbajack.Lib /// /// /// - public static async Task GetModIni(Hash hash) + public static async Task GetModIni(Hash hash) { var client = new Common.Http.Client(); try diff --git a/Wabbajack.Lib/MO2Installer.cs b/Wabbajack.Lib/MO2Installer.cs index 050ab03a..ab4af57a 100644 --- a/Wabbajack.Lib/MO2Installer.cs +++ b/Wabbajack.Lib/MO2Installer.cs @@ -21,6 +21,7 @@ using Directory = Alphaleonis.Win32.Filesystem.Directory; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; using SectionData = Wabbajack.Common.SectionData; +#nullable enable namespace Wabbajack.Lib { @@ -32,6 +33,8 @@ namespace Wabbajack.Lib public AbsolutePath? GameFolder { get; set; } + public GameMetaData Game { get; } + public MO2Installer(AbsolutePath archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters) : base( archive: archive, @@ -41,6 +44,7 @@ namespace Wabbajack.Lib parameters: parameters, steps: 20) { + Game = ModList.GameType.MetaData(); } protected override async Task _Begin(CancellationToken cancel) @@ -50,27 +54,26 @@ namespace Wabbajack.Lib Utils.Log("Configuring Processor"); Queue.SetActiveThreadsObservable(ConstructDynamicNumThreads(await RecommendQueueSize())); - var game = ModList.GameType.MetaData(); if (GameFolder == null) - GameFolder = game.GameLocation(); + GameFolder = Game.GameLocation(); if (GameFolder == null) { - var otherGame = game.CommonlyConfusedWith.Where(g => g.MetaData().IsInstalled).Select(g => g.MetaData()).FirstOrDefault(); + var otherGame = Game.CommonlyConfusedWith.Where(g => g.MetaData().IsInstalled).Select(g => g.MetaData()).FirstOrDefault(); if (otherGame != null) { await Utils.Log(new CriticalFailureIntervention( - $"In order to do a proper install Wabbajack needs to know where your {game.HumanFriendlyGameName} folder resides. However this game doesn't seem to be installed, we did however find a installed " + + $"In order to do a proper install Wabbajack needs to know where your {Game.HumanFriendlyGameName} folder resides. However this game doesn't seem to be installed, we did however find a installed " + $"copy of {otherGame.HumanFriendlyGameName}, did you install the wrong game?", - $"Could not locate {game.HumanFriendlyGameName}")) + $"Could not locate {Game.HumanFriendlyGameName}")) .Task; } else { await Utils.Log(new CriticalFailureIntervention( - $"In order to do a proper install Wabbajack needs to know where your {game.HumanFriendlyGameName} folder resides. However this game doesn't seem to be installed", - $"Could not locate {game.HumanFriendlyGameName}")) + $"In order to do a proper install Wabbajack needs to know where your {Game.HumanFriendlyGameName} folder resides. However this game doesn't seem to be installed", + $"Could not locate {Game.HumanFriendlyGameName}")) .Task; } @@ -170,7 +173,6 @@ namespace Wabbajack.Lib private void CreateOutputMods() { - OutputFolder.Combine("profiles") .EnumerateFiles(true) .Where(f => f.FileName == Consts.SettingsIni) @@ -236,7 +238,7 @@ namespace Wabbajack.Lib foreach (var esm in ModList.Directives.OfType().ToList()) { var filename = esm.To.FileName; - var gameFile = GameFolder.Value.Combine((RelativePath)"Data", filename); + var gameFile = GameFolder!.Value.Combine((RelativePath)"Data", filename); Utils.Log($"Validating {filename}"); var hash = gameFile.FileHash(); if (hash != esm.SourceESMHash) @@ -311,7 +313,7 @@ namespace Wabbajack.Lib private async Task GenerateCleanedESM(CleanedESM directive) { var filename = directive.To.FileName; - var gameFile = GameFolder.Value.Combine((RelativePath)"Data", filename); + var gameFile = GameFolder!.Value.Combine((RelativePath)"Data", filename); Info($"Generating cleaned ESM for {filename}"); if (!gameFile.Exists) throw new InvalidDataException($"Missing {filename} at {gameFile}"); Status($"Hashing game version of {filename}"); @@ -376,8 +378,8 @@ namespace Wabbajack.Lib { var data = Encoding.UTF8.GetString(await LoadBytesFromPath(directive.SourceDataID)); - data = data.Replace(Consts.GAME_PATH_MAGIC_BACK, (string)GameFolder); - data = data.Replace(Consts.GAME_PATH_MAGIC_DOUBLE_BACK, ((string)GameFolder).Replace("\\", "\\\\")); + data = data.Replace(Consts.GAME_PATH_MAGIC_BACK, (string)GameFolder!); + data = data.Replace(Consts.GAME_PATH_MAGIC_DOUBLE_BACK, ((string)GameFolder!).Replace("\\", "\\\\")); data = data.Replace(Consts.GAME_PATH_MAGIC_FORWARD, ((string)GameFolder).Replace("\\", "/")); data = data.Replace(Consts.MO2_PATH_MAGIC_BACK, (string)OutputFolder); diff --git a/Wabbajack.Lib/Manifest.cs b/Wabbajack.Lib/Manifest.cs index 4058e922..00ce5d6a 100644 --- a/Wabbajack.Lib/Manifest.cs +++ b/Wabbajack.Lib/Manifest.cs @@ -2,6 +2,7 @@ using System.Linq; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; +#nullable enable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/SystemParameters.cs b/Wabbajack.Lib/SystemParameters.cs index 1964b8c1..2dc7c9d5 100644 --- a/Wabbajack.Lib/SystemParameters.cs +++ b/Wabbajack.Lib/SystemParameters.cs @@ -1,4 +1,5 @@ using System; +#nullable enable namespace Wabbajack.Lib { @@ -14,9 +15,9 @@ namespace Wabbajack.Lib public int ScreenWidth { get; set; } public long VideoMemorySize { get; set; } public long SystemMemorySize { get; set; } - - public Version WindowsVersion { get; set; } - + + public Version WindowsVersion { get; set; } = Environment.OSVersion.Version; + /// /// Value used in LE ENBs for VideoMemorySizeMb /// diff --git a/Wabbajack.Lib/ViewModel.cs b/Wabbajack.Lib/ViewModel.cs index 6b2b06fc..ce5da622 100644 --- a/Wabbajack.Lib/ViewModel.cs +++ b/Wabbajack.Lib/ViewModel.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Reactive.Disposables; using System.Runtime.CompilerServices; +#nullable enable namespace Wabbajack.Lib { @@ -24,7 +25,7 @@ namespace Wabbajack.Lib protected void RaiseAndSetIfChanged( ref T item, T newItem, - [CallerMemberName] string propertyName = null) + [CallerMemberName] string? propertyName = null) { if (EqualityComparer.Default.Equals(item, newItem)) return; item = newItem; diff --git a/Wabbajack.Lib/VortexCompiler.cs b/Wabbajack.Lib/VortexCompiler.cs index 4ad94116..8f0e3022 100644 --- a/Wabbajack.Lib/VortexCompiler.cs +++ b/Wabbajack.Lib/VortexCompiler.cs @@ -15,6 +15,7 @@ using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.Validation; using File = Alphaleonis.Win32.Filesystem.File; using Game = Wabbajack.Common.Game; +#nullable enable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/VortexInstaller.cs b/Wabbajack.Lib/VortexInstaller.cs index 78ba8d1e..dd0ad998 100644 --- a/Wabbajack.Lib/VortexInstaller.cs +++ b/Wabbajack.Lib/VortexInstaller.cs @@ -11,6 +11,7 @@ using Directory = Alphaleonis.Win32.Filesystem.Directory; using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; +#nullable disable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/zEditIntegration.cs b/Wabbajack.Lib/zEditIntegration.cs index a4e67b0e..3b4dbb72 100644 --- a/Wabbajack.Lib/zEditIntegration.cs +++ b/Wabbajack.Lib/zEditIntegration.cs @@ -9,6 +9,7 @@ using Directory = Alphaleonis.Win32.Filesystem.Directory; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; using System.Threading.Tasks; +#nullable disable namespace Wabbajack.Lib { diff --git a/Wabbajack/Util/SystemParametersConstructor.cs b/Wabbajack/Util/SystemParametersConstructor.cs index 28abeafb..cad457b9 100644 --- a/Wabbajack/Util/SystemParametersConstructor.cs +++ b/Wabbajack/Util/SystemParametersConstructor.cs @@ -56,7 +56,6 @@ namespace Wabbajack.Util ScreenHeight = height, VideoMemorySize = video_memory, SystemMemorySize = (long)memory.ullTotalPhys, - WindowsVersion = Environment.OSVersion.Version }; } } From 86641d01dfc87e6e8b0304c3a8ec4118fbf7be0b Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 13:14:05 -0500 Subject: [PATCH 05/23] Wabbajack.Lib Compilation steps nullable enabled --- .editorconfig | 8 ++- Wabbajack.BuildServer/Controllers/Jobs.cs | 2 +- .../CompilationSteps/ACompilationStep.cs | 3 +- .../CompilationSteps/DeconstructBSAs.cs | 3 +- Wabbajack.Lib/CompilationSteps/DirectMatch.cs | 3 +- Wabbajack.Lib/CompilationSteps/DropAll.cs | 3 +- .../{IStackStep.cs => ICompilationStep.cs} | 3 +- .../CompilationSteps/IgnoreDisabledMods.cs | 3 +- .../CompilationSteps/IgnoreEndsWith.cs | 11 ++-- .../CompilationSteps/IgnoreGameFiles.cs | 3 +- .../IgnoreGameFilesIfGameFolderFilesExist.cs | 3 +- .../CompilationSteps/IgnorePathContains.cs | 9 +-- Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs | 9 +-- .../CompilationSteps/IgnoreStartsWith.cs | 9 +-- .../IgnoreWabbajackInstallCruft.cs | 3 +- Wabbajack.Lib/CompilationSteps/IncludeAll.cs | 3 +- .../CompilationSteps/IncludeAllConfigs.cs | 3 +- .../CompilationSteps/IncludeDummyESPs.cs | 3 +- .../CompilationSteps/IncludeLOOTFiles.cs | 3 +- .../CompilationSteps/IncludeModIniData.cs | 3 +- .../CompilationSteps/IncludeOtherProfiles.cs | 3 +- .../CompilationSteps/IncludePatches.cs | 12 ++-- .../CompilationSteps/IncludePropertyFiles.cs | 3 +- .../CompilationSteps/IncludeRegex.cs | 9 +-- .../IncludeSteamWorkshopItems.cs | 5 +- .../IncludeStubbedConfigfiles.cs | 5 +- .../CompilationSteps/IncludeTaggedMods.cs | 9 +-- .../CompilationSteps/IncludeThisProfile.cs | 3 +- .../IncludeVortexDeployment.cs | 3 +- .../CompilationSteps/PatchStockESMs.cs | 3 +- Wabbajack.Lib/zEditIntegration.cs | 62 +++++++++---------- 31 files changed, 108 insertions(+), 99 deletions(-) rename Wabbajack.Lib/CompilationSteps/{IStackStep.cs => ICompilationStep.cs} (77%) diff --git a/.editorconfig b/.editorconfig index 5b46bd60..24eda6c4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -184,4 +184,10 @@ dotnet_diagnostic.CS8609.severity = error dotnet_diagnostic.CS8714.severity = error # CS8605: Unboxing a possibly null value. -dotnet_diagnostic.CS8605.severity = error \ No newline at end of file +dotnet_diagnostic.CS8605.severity = error + +# CS8613: Nullability of reference types in return type doesn't match implicitly implemented member. +dotnet_diagnostic.CS8613.severity = error + +# CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. +dotnet_diagnostic.CS8632.severity = error \ No newline at end of file diff --git a/Wabbajack.BuildServer/Controllers/Jobs.cs b/Wabbajack.BuildServer/Controllers/Jobs.cs index 210bf318..875ad9c3 100644 --- a/Wabbajack.BuildServer/Controllers/Jobs.cs +++ b/Wabbajack.BuildServer/Controllers/Jobs.cs @@ -22,7 +22,7 @@ namespace Wabbajack.BuildServer.Controllers public async Task EnqueueJob(string JobName) { var jobtype = AJobPayload.NameToType[JobName]; - var job = new Job{Priority = Job.JobPriority.High, Payload = (AJobPayload)jobtype.GetConstructor(new Type[0]).Invoke(new object?[0])}; + var job = new Job{Priority = Job.JobPriority.High, Payload = (AJobPayload)jobtype.GetConstructor(new Type[0]).Invoke(new object[0])}; await SQL.EnqueueJob(job); return job.Id; } diff --git a/Wabbajack.Lib/CompilationSteps/ACompilationStep.cs b/Wabbajack.Lib/CompilationSteps/ACompilationStep.cs index 9dc0e547..4427334f 100644 --- a/Wabbajack.Lib/CompilationSteps/ACompilationStep.cs +++ b/Wabbajack.Lib/CompilationSteps/ACompilationStep.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -11,7 +12,7 @@ namespace Wabbajack.Lib.CompilationSteps _compiler = compiler; } - public abstract ValueTask Run(RawSourceFile source); + public abstract ValueTask Run(RawSourceFile source); public abstract IState GetState(); } } diff --git a/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs b/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs index 19d00fcb..d8ea17f5 100644 --- a/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs +++ b/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Common.StatusFeed.Errors; using Wabbajack.VirtualFileSystem; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -51,7 +52,7 @@ namespace Wabbajack.Lib.CompilationSteps return new State(); } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!Consts.SupportedBSAs.Contains(source.Path.Extension)) return null; diff --git a/Wabbajack.Lib/CompilationSteps/DirectMatch.cs b/Wabbajack.Lib/CompilationSteps/DirectMatch.cs index 807184f4..6f883117 100644 --- a/Wabbajack.Lib/CompilationSteps/DirectMatch.cs +++ b/Wabbajack.Lib/CompilationSteps/DirectMatch.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -11,7 +12,7 @@ namespace Wabbajack.Lib.CompilationSteps { } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!_compiler.IndexedFiles.TryGetValue(source.Hash, out var found)) return null; var result = source.EvolveTo(); diff --git a/Wabbajack.Lib/CompilationSteps/DropAll.cs b/Wabbajack.Lib/CompilationSteps/DropAll.cs index 2d5c65a1..0c3a6fc4 100644 --- a/Wabbajack.Lib/CompilationSteps/DropAll.cs +++ b/Wabbajack.Lib/CompilationSteps/DropAll.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -10,7 +11,7 @@ namespace Wabbajack.Lib.CompilationSteps { } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { var result = source.EvolveTo(); result.Reason = "No Match in Stack"; diff --git a/Wabbajack.Lib/CompilationSteps/IStackStep.cs b/Wabbajack.Lib/CompilationSteps/ICompilationStep.cs similarity index 77% rename from Wabbajack.Lib/CompilationSteps/IStackStep.cs rename to Wabbajack.Lib/CompilationSteps/ICompilationStep.cs index 1c427edc..68b8b73b 100644 --- a/Wabbajack.Lib/CompilationSteps/IStackStep.cs +++ b/Wabbajack.Lib/CompilationSteps/ICompilationStep.cs @@ -1,10 +1,11 @@ using System.Threading.Tasks; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { public interface ICompilationStep { - ValueTask Run(RawSourceFile source); + ValueTask Run(RawSourceFile source); IState GetState(); } diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs b/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs index e066fc66..f9b9f1bc 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -25,7 +26,7 @@ namespace Wabbajack.Lib.CompilationSteps .ToList(); } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!source.AbsolutePath.InFolder(_mo2Compiler.MO2ModsFolder)) return null; if (_allEnabledMods.Any(mod => source.AbsolutePath.InFolder(mod))) diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreEndsWith.cs b/Wabbajack.Lib/CompilationSteps/IgnoreEndsWith.cs index adec2b87..53b44621 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreEndsWith.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreEndsWith.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Newtonsoft.Json; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -14,7 +15,7 @@ namespace Wabbajack.Lib.CompilationSteps _reason = $"Ignored because path ends with {postfix}"; } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!((string)source.Path).EndsWith(_postfix)) return null; var result = source.EvolveTo(); @@ -30,17 +31,13 @@ namespace Wabbajack.Lib.CompilationSteps [JsonObject("IgnoreEndsWith")] public class State : IState { + public string Postfix { get; set; } + public State(string postfix) { Postfix = postfix; } - public State() - { - } - - public string Postfix { get; set; } - public ICompilationStep CreateStep(ACompiler compiler) { return new IgnoreEndsWith(compiler, Postfix); diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreGameFiles.cs b/Wabbajack.Lib/CompilationSteps/IgnoreGameFiles.cs index 30889a77..9b95d35d 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreGameFiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreGameFiles.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -13,7 +14,7 @@ namespace Wabbajack.Lib.CompilationSteps _startDir = Consts.GameFolderFilesDir + "\\"; } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!((string)source.Path).StartsWith(_startDir)) return null; var i = source.EvolveTo(); diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs b/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs index 420a17a2..59026899 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -15,7 +16,7 @@ namespace Wabbajack.Lib.CompilationSteps _gameFolder = compiler.GamePath; } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (_gameFolderFilesExists) { diff --git a/Wabbajack.Lib/CompilationSteps/IgnorePathContains.cs b/Wabbajack.Lib/CompilationSteps/IgnorePathContains.cs index 25094e16..1a8c627b 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnorePathContains.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnorePathContains.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Newtonsoft.Json; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -14,7 +15,7 @@ namespace Wabbajack.Lib.CompilationSteps _reason = $"Ignored because path contains {_pattern}"; } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!((string)source.Path).Contains(_pattern)) return null; var result = source.EvolveTo(); @@ -30,17 +31,13 @@ namespace Wabbajack.Lib.CompilationSteps [JsonObject("IgnorePathContains")] public class State : IState { - public State() - { - } + public string Pattern { get; set; } public State(string pattern) { Pattern = pattern; } - public string Pattern { get; set; } - public ICompilationStep CreateStep(ACompiler compiler) { return new IgnorePathContains(compiler, Pattern); diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs b/Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs index 7c004d2a..abf48183 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs @@ -1,6 +1,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Newtonsoft.Json; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -17,7 +18,7 @@ namespace Wabbajack.Lib.CompilationSteps _regex = new Regex(pattern); } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!_regex.IsMatch((string)source.Path)) return null; var result = source.EvolveTo(); @@ -33,17 +34,13 @@ namespace Wabbajack.Lib.CompilationSteps [JsonObject("IgnorePattern")] public class State : IState { - public State() - { - } + public string Pattern { get; set; } public State(string pattern) { Pattern = pattern; } - public string Pattern { get; set; } - public ICompilationStep CreateStep(ACompiler compiler) { return new IgnoreRegex(compiler, Pattern); diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreStartsWith.cs b/Wabbajack.Lib/CompilationSteps/IgnoreStartsWith.cs index ce345a53..087ea169 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreStartsWith.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreStartsWith.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Newtonsoft.Json; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -14,7 +15,7 @@ namespace Wabbajack.Lib.CompilationSteps _reason = string.Format("Ignored because path starts with {0}", _prefix); } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!((string)source.Path).StartsWith(_prefix)) { @@ -35,17 +36,13 @@ namespace Wabbajack.Lib.CompilationSteps [JsonObject("IgnoreStartsWith")] public class State : IState { - public State() - { - } + public string Prefix { get; set; } public State(string prefix) { Prefix = prefix; } - public string Prefix { get; set; } - public ICompilationStep CreateStep(ACompiler compiler) { return new IgnoreStartsWith(compiler, Prefix); diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreWabbajackInstallCruft.cs b/Wabbajack.Lib/CompilationSteps/IgnoreWabbajackInstallCruft.cs index ae46fa03..c1f36243 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreWabbajackInstallCruft.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreWabbajackInstallCruft.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -19,7 +20,7 @@ namespace Wabbajack.Lib.CompilationSteps }; } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!_cruftFiles.Any(f => source.Path.StartsWith(f))) return null; var result = source.EvolveTo(); diff --git a/Wabbajack.Lib/CompilationSteps/IncludeAll.cs b/Wabbajack.Lib/CompilationSteps/IncludeAll.cs index 9f836158..6f229c45 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeAll.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeAll.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -10,7 +11,7 @@ namespace Wabbajack.Lib.CompilationSteps { } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { var inline = source.EvolveTo(); inline.SourceDataID = await _compiler.IncludeFile(await source.AbsolutePath.ReadAllBytesAsync()); diff --git a/Wabbajack.Lib/CompilationSteps/IncludeAllConfigs.cs b/Wabbajack.Lib/CompilationSteps/IncludeAllConfigs.cs index 10ae1e26..eb73f724 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeAllConfigs.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeAllConfigs.cs @@ -2,6 +2,7 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -11,7 +12,7 @@ namespace Wabbajack.Lib.CompilationSteps { } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!Consts.ConfigFileExtensions.Contains(source.Path.Extension)) return null; var result = source.EvolveTo(); diff --git a/Wabbajack.Lib/CompilationSteps/IncludeDummyESPs.cs b/Wabbajack.Lib/CompilationSteps/IncludeDummyESPs.cs index 5dd9f1a7..127d7555 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeDummyESPs.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeDummyESPs.cs @@ -2,6 +2,7 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -11,7 +12,7 @@ namespace Wabbajack.Lib.CompilationSteps { } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (source.AbsolutePath.Extension != Consts.ESP && source.AbsolutePath.Extension != Consts.ESM) return null; diff --git a/Wabbajack.Lib/CompilationSteps/IncludeLOOTFiles.cs b/Wabbajack.Lib/CompilationSteps/IncludeLOOTFiles.cs index 7bc05446..a34e0a3f 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeLOOTFiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeLOOTFiles.cs @@ -2,6 +2,7 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -14,7 +15,7 @@ namespace Wabbajack.Lib.CompilationSteps _prefix = Consts.LOOTFolderFilesDir + "\\"; } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!source.Path.StartsWith(_prefix)) return null; var result = source.EvolveTo(); diff --git a/Wabbajack.Lib/CompilationSteps/IncludeModIniData.cs b/Wabbajack.Lib/CompilationSteps/IncludeModIniData.cs index c5d3614a..70bc66b8 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeModIniData.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeModIniData.cs @@ -2,6 +2,7 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -11,7 +12,7 @@ namespace Wabbajack.Lib.CompilationSteps { } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!source.Path.StartsWith("mods\\") || source.Path.FileName != Consts.MetaIni) return null; var e = source.EvolveTo(); diff --git a/Wabbajack.Lib/CompilationSteps/IncludeOtherProfiles.cs b/Wabbajack.Lib/CompilationSteps/IncludeOtherProfiles.cs index c643b2eb..a6190347 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeOtherProfiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeOtherProfiles.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -23,7 +24,7 @@ namespace Wabbajack.Lib.CompilationSteps .ToList(); } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!source.AbsolutePath.InFolder(_modProfilesFolder)) return null; if (_profiles.Any(profile => source.AbsolutePath.InFolder(profile))) return null; diff --git a/Wabbajack.Lib/CompilationSteps/IncludePatches.cs b/Wabbajack.Lib/CompilationSteps/IncludePatches.cs index e99fcf9a..228cc7e3 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludePatches.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludePatches.cs @@ -6,17 +6,18 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.VirtualFileSystem; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { public class IncludePatches : ACompilationStep { private readonly Dictionary> _indexed; - private VirtualFile _bsa; + private VirtualFile? _bsa; private Dictionary _indexedByName; private MO2Compiler _mo2Compiler; - public IncludePatches(ACompiler compiler, VirtualFile constructingFromBSA = null) : base(compiler) + public IncludePatches(ACompiler compiler, VirtualFile? constructingFromBSA = null) : base(compiler) { _bsa = constructingFromBSA; _mo2Compiler = (MO2Compiler)compiler; @@ -30,9 +31,8 @@ namespace Wabbajack.Lib.CompilationSteps .ToDictionary(f => f.FullPath.FileName); } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { - var name = source.File.Name.FileName; RelativePath nameWithoutExt = name; if (name.Extension == Consts.MOHIDDEN) @@ -41,7 +41,7 @@ namespace Wabbajack.Lib.CompilationSteps if (!_indexed.TryGetValue(name, out var choices)) _indexed.TryGetValue(nameWithoutExt, out choices); - dynamic modIni = null; + dynamic? modIni = null; if (source.AbsolutePath.InFolder(_mo2Compiler.MO2ModsFolder)) { if (_bsa == null) @@ -55,7 +55,7 @@ namespace Wabbajack.Lib.CompilationSteps var installationFile = (RelativePath)modIni?.General?.installationFile; - VirtualFile found = null; + VirtualFile? found = null; // Find based on exact file name + ext if (choices != null) diff --git a/Wabbajack.Lib/CompilationSteps/IncludePropertyFiles.cs b/Wabbajack.Lib/CompilationSteps/IncludePropertyFiles.cs index 3ccd5e54..eb877762 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludePropertyFiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludePropertyFiles.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -14,7 +15,7 @@ namespace Wabbajack.Lib.CompilationSteps { } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { var files = new HashSet { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeRegex.cs b/Wabbajack.Lib/CompilationSteps/IncludeRegex.cs index a7482285..e5fbda99 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeRegex.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeRegex.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -16,7 +17,7 @@ namespace Wabbajack.Lib.CompilationSteps _regex = new Regex(pattern); } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!_regex.IsMatch((string)source.Path)) return null; @@ -33,17 +34,13 @@ namespace Wabbajack.Lib.CompilationSteps [JsonObject("IncludeRegex")] public class State : IState { - public State() - { - } + public string Pattern { get; set; } public State(string pattern) { Pattern = pattern; } - public string Pattern { get; set; } - public ICompilationStep CreateStep(ACompiler compiler) { return new IncludeRegex(compiler, Pattern); diff --git a/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs b/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs index ad6b3200..68cd72bd 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Wabbajack.Common; using Wabbajack.Common.StoreHandlers; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -18,7 +19,7 @@ namespace Wabbajack.Lib.CompilationSteps _game = steamGame; } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!_regex.IsMatch((string)source.Path)) return null; @@ -31,7 +32,7 @@ namespace Wabbajack.Lib.CompilationSteps if (id == 0) return null; - SteamWorkshopItem item = null; + SteamWorkshopItem? item = null; _game.WorkshopItems.Where(i => i.ItemID == id).Do(i => item = i); if (item == null) return null; diff --git a/Wabbajack.Lib/CompilationSteps/IncludeStubbedConfigfiles.cs b/Wabbajack.Lib/CompilationSteps/IncludeStubbedConfigfiles.cs index 32e41955..b1c1abff 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeStubbedConfigfiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeStubbedConfigfiles.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -15,7 +16,7 @@ namespace Wabbajack.Lib.CompilationSteps _mo2Compiler = (MO2Compiler) compiler; } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { return Consts.ConfigFileExtensions.Contains(source.Path.Extension) ? await RemapFile(source) : null; } @@ -25,7 +26,7 @@ namespace Wabbajack.Lib.CompilationSteps return new State(); } - private async Task RemapFile(RawSourceFile source) + private async Task RemapFile(RawSourceFile source) { var data = await source.AbsolutePath.ReadAllTextAsync(); var originalData = data; diff --git a/Wabbajack.Lib/CompilationSteps/IncludeTaggedMods.cs b/Wabbajack.Lib/CompilationSteps/IncludeTaggedMods.cs index d88deece..2409568a 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeTaggedMods.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeTaggedMods.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -26,7 +27,7 @@ namespace Wabbajack.Lib.CompilationSteps }).Select(kv => $"mods\\{kv.Key}\\"); } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!source.Path.StartsWith(Consts.MO2ModFolderName)) return null; foreach (var modpath in _includeDirectly) @@ -48,17 +49,13 @@ namespace Wabbajack.Lib.CompilationSteps [JsonObject("IncludeTaggedMods")] public class State : IState { - public State() - { - } + public string Tag { get; set; } public State(string tag) { Tag = tag; } - public string Tag { get; set; } - public ICompilationStep CreateStep(ACompiler compiler) { return new IncludeTaggedMods(compiler, Tag); diff --git a/Wabbajack.Lib/CompilationSteps/IncludeThisProfile.cs b/Wabbajack.Lib/CompilationSteps/IncludeThisProfile.cs index 2200c2fb..d01cf628 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeThisProfile.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeThisProfile.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -19,7 +20,7 @@ namespace Wabbajack.Lib.CompilationSteps _correctProfiles = _mo2Compiler.SelectedProfiles.Select(p => _mo2Compiler.MO2ProfileDir.Parent.Combine(p)).ToList(); } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { if (!_correctProfiles.Any(p => source.AbsolutePath.InFolder(p))) return null; diff --git a/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs b/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs index e9a54343..303afbfa 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -12,7 +13,7 @@ namespace Wabbajack.Lib.CompilationSteps { } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { // * TODO I don't know what this does /* diff --git a/Wabbajack.Lib/CompilationSteps/PatchStockESMs.cs b/Wabbajack.Lib/CompilationSteps/PatchStockESMs.cs index e71dfc0c..fabc3072 100644 --- a/Wabbajack.Lib/CompilationSteps/PatchStockESMs.cs +++ b/Wabbajack.Lib/CompilationSteps/PatchStockESMs.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using Wabbajack.Common; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; +#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -16,7 +17,7 @@ namespace Wabbajack.Lib.CompilationSteps _mo2Compiler = (MO2Compiler) compiler; } - public override async ValueTask Run(RawSourceFile source) + public override async ValueTask Run(RawSourceFile source) { var filename = source.Path.FileName; var gameFile = _mo2Compiler.GamePath.Combine((RelativePath)"Data", filename); diff --git a/Wabbajack.Lib/zEditIntegration.cs b/Wabbajack.Lib/zEditIntegration.cs index 3b4dbb72..5590ddf8 100644 --- a/Wabbajack.Lib/zEditIntegration.cs +++ b/Wabbajack.Lib/zEditIntegration.cs @@ -9,40 +9,23 @@ using Directory = Alphaleonis.Win32.Filesystem.Directory; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; using System.Threading.Tasks; -#nullable disable +#nullable enable namespace Wabbajack.Lib { public class zEditIntegration { - private static MO2Compiler _mo2Compiler; - - public static AbsolutePath FindzEditPath(ACompiler compiler) - { - _mo2Compiler = (MO2Compiler) compiler; - var executables = _mo2Compiler.MO2Ini.customExecutables; - if (executables.size == null) return default; - - foreach (var idx in Enumerable.Range(1, int.Parse(executables.size))) - { - var path = (string)executables[$"{idx}\\binary"]; - if (path == null) continue; - - if (path.EndsWith("zEdit.exe")) - return (AbsolutePath)path; - } - - return default; - } - public class IncludeZEditPatches : ACompilationStep { - private readonly Dictionary _mergesIndexed; + private readonly Dictionary _mergesIndexed = new Dictionary(); private bool _disabled = true; - public IncludeZEditPatches(ACompiler compiler) : base(compiler) + private MO2Compiler _mo2Compiler; + + public IncludeZEditPatches(MO2Compiler compiler) : base(compiler) { + _mo2Compiler = compiler; var zEditPath = FindzEditPath(compiler); var havezEdit = zEditPath != default; @@ -127,7 +110,24 @@ namespace Wabbajack.Lib _disabled = false; } - public override async ValueTask Run(RawSourceFile source) + public static AbsolutePath FindzEditPath(MO2Compiler compiler) + { + var executables = compiler.MO2Ini.customExecutables; + if (executables.size == null) return default; + + foreach (var idx in Enumerable.Range(1, int.Parse(executables.size))) + { + var path = (string)executables[$"{idx}\\binary"]; + if (path == null) continue; + + if (path.EndsWith("zEdit.exe")) + return (AbsolutePath)path; + } + + return default; + } + + public override async ValueTask Run(RawSourceFile source) { if (_disabled) return null; if (!_mergesIndexed.TryGetValue(source.AbsolutePath, out var merge)) @@ -210,14 +210,14 @@ namespace Wabbajack.Lib { public ICompilationStep CreateStep(ACompiler compiler) { - return new IncludeZEditPatches(compiler); + return new IncludeZEditPatches((MO2Compiler)compiler); } } } public class zEditSettings { - public string modManager; + public string modManager = string.Empty; public AbsolutePath managerPath; public AbsolutePath modsPath; public AbsolutePath mergePath; @@ -225,16 +225,16 @@ namespace Wabbajack.Lib public class zEditMerge { - public string name; - public string filename; - public List plugins; + public string name = string.Empty; + public string filename = string.Empty; + public List plugins = new List(); } public class zEditMergePlugin { - public string filename; - public string dataFolder; + public string? filename; + public string? dataFolder; } public static void VerifyMerges(MO2Compiler compiler) From 5a38f40a66bf4488f866b8d0d53ab57209ac4246 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 13:57:02 -0500 Subject: [PATCH 06/23] GameMetaData.TryGetGameLocation() Added choice of nullable return or not --- .../Models/Jobs/EnqueueAllGameFiles.cs | 6 +++--- Wabbajack.Common/GameMetaData.cs | 11 +++++++++-- Wabbajack.Common/StoreHandlers/StoreHandler.cs | 2 +- Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs | 2 +- Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs | 5 ++--- Wabbajack.Test/DownloaderTests.cs | 2 +- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs b/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs index 7a393b4e..c1983081 100644 --- a/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs +++ b/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs @@ -21,12 +21,12 @@ namespace Wabbajack.BuildServer.Models.Jobs Utils.Log($"Indexing game files"); var states = GameRegistry.Games.Values .Where(game => game.GameLocation() != null && game.MainExecutable != null) - .SelectMany(game => game.GameLocation().Value.EnumerateFiles() + .SelectMany(game => game.GameLocation().EnumerateFiles() .Select(file => new GameFileSourceDownloader.State { Game = game.Game, GameVersion = game.InstalledVersion, - GameFile = file.RelativeTo(game.GameLocation().Value), + GameFile = file.RelativeTo(game.GameLocation()), })) .ToList(); @@ -40,7 +40,7 @@ namespace Wabbajack.BuildServer.Models.Jobs await states.PMap(queue, async state => { - var path = state.Game.MetaData().GameLocation().Value.Combine(state.GameFile); + var path = state.Game.MetaData().GameLocation().Combine(state.GameFile); Utils.Log($"Hashing Game file {path}"); try { diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index 80b70bb5..b8d558df 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -99,9 +99,16 @@ namespace Wabbajack.Common public string? MainExecutable { get; internal set; } - public AbsolutePath? GameLocation() + public AbsolutePath? TryGetGameLocation() { - return Consts.TestMode ? AbsolutePath.GetCurrentDirectory() : StoreHandler.Instance.GetGamePath(Game); + return Consts.TestMode ? AbsolutePath.GetCurrentDirectory() : StoreHandler.Instance.TryGetGamePath(Game); + } + + public AbsolutePath GameLocation() + { + var ret = TryGetGameLocation(); + if (ret == null) throw new ArgumentNullException(); + return ret.Value; } } diff --git a/Wabbajack.Common/StoreHandlers/StoreHandler.cs b/Wabbajack.Common/StoreHandlers/StoreHandler.cs index 52aaf5c5..0547aa28 100644 --- a/Wabbajack.Common/StoreHandlers/StoreHandler.cs +++ b/Wabbajack.Common/StoreHandlers/StoreHandler.cs @@ -52,7 +52,7 @@ namespace Wabbajack.Common.StoreHandlers } } - public AbsolutePath? GetGamePath(Game game) + public AbsolutePath? TryGetGamePath(Game game) { return StoreGames.FirstOrDefault(g => g.Game == game)?.Path; } diff --git a/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs b/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs index c05d4ed1..879b1025 100644 --- a/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs +++ b/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs @@ -68,7 +68,7 @@ namespace Wabbajack.Lib.Downloaders public static async Task Login(Game game) { var metadata = game.MetaData(); - var gamePath = metadata.GameLocation()?.Combine(metadata.MainExecutable); + var gamePath = metadata.GameLocation().Combine(metadata.MainExecutable); var info = new ProcessStartInfo { FileName = @"Downloaders\BethesdaNet\bethnetlogin.exe", diff --git a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs index 45f1e80e..dd351330 100644 --- a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs @@ -20,10 +20,9 @@ namespace Wabbajack.Lib.Downloaders var game = GameRegistry.GetByFuzzyName(gameName); if (game == null) return null; - var path = game.GameLocation(); + var path = game.TryGetGameLocation(); var filePath = path?.Combine(gameFile); - if (!filePath?.Exists ?? false) return null; @@ -52,7 +51,7 @@ namespace Wabbajack.Lib.Downloaders public string GameVersion { get; set; } [JsonIgnore] - internal AbsolutePath SourcePath => Game.MetaData().GameLocation().Value.Combine(GameFile); + internal AbsolutePath SourcePath => Game.MetaData().GameLocation().Combine(GameFile); [JsonIgnore] public override object[] PrimaryKey { get => new object[] {Game, GameVersion, GameFile}; } diff --git a/Wabbajack.Test/DownloaderTests.cs b/Wabbajack.Test/DownloaderTests.cs index e1d52437..08614e99 100644 --- a/Wabbajack.Test/DownloaderTests.cs +++ b/Wabbajack.Test/DownloaderTests.cs @@ -415,7 +415,7 @@ namespace Wabbajack.Test await converted.Download(new Archive { Name = "Update.esm" }, filename.Path); Assert.Equal(Hash.FromBase64("/DLG/LjdGXI="), await Utils.FileHashAsync(filename.Path)); - Assert.Equal(await filename.Path.ReadAllBytesAsync(), await Game.SkyrimSpecialEdition.MetaData().GameLocation()?.Combine("Data/Update.esm").ReadAllBytesAsync()); + Assert.Equal(await filename.Path.ReadAllBytesAsync(), await Game.SkyrimSpecialEdition.MetaData().GameLocation().Combine("Data/Update.esm").ReadAllBytesAsync()); Consts.TestMode = true; } From a7ad4f1f16a7c0cc37565932d610e49b2c617223 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 14:21:28 -0500 Subject: [PATCH 07/23] TryGetByFuzzyName Added choice for nullable return --- Wabbajack.Common/GameMetaData.cs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index b8d558df..4f8a7a67 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -163,16 +163,24 @@ namespace Wabbajack.Common } /// - /// Tries to parse game data from an arbitrary string. Tries first via parsing as a game Enum, then by Nexus name, - /// - /// - public static GameMetaData? GetByFuzzyName(string someName) + /// Parse game data from an arbitrary string. Tries first via parsing as a game Enum, then by Nexus name. + /// Name to query + /// GameMetaData found + /// If string could not be translated to a game + public static GameMetaData GetByFuzzyName(string someName) + { + return TryGetByFuzzyName(someName) ?? throw new ArgumentNullException($"{someName} could not be translated to a game"); + } + + /// + /// Tries to parse game data from an arbitrary string. Tries first via parsing as a game Enum, then by Nexus name. + /// Name to query + /// GameMetaData if found, otherwise null + public static GameMetaData? TryGetByFuzzyName(string someName) { if (Enum.TryParse(typeof(Game), someName, true, out var metadata)) return ((Game)metadata!).MetaData(); - GameMetaData? result = null; - - result = GetByNexusName(someName); + GameMetaData? result = GetByNexusName(someName); if (result != null) return result; result = GetByMO2ArchiveName(someName); From a29eb93caf93a43a098dec505f6a75a930ea990c Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 15:20:34 -0500 Subject: [PATCH 08/23] Wabbajack.Lib downloaders enable nullable --- .../ModListValidationTests.cs | 2 +- Wabbajack.BuildServer.Test/ModlistUpdater.cs | 10 +- .../Models/Jobs/EnqueueAllGameFiles.cs | 6 +- .../Models/Jobs/IndexDynDOLOD.cs | 5 +- .../Models/Jobs/UploadToCDN.cs | 5 +- .../Downloaders/AFKModsDownloader.cs | 1 + .../Downloaders/AbstractDownloadState.cs | 17 ++-- .../Downloaders/AbstractIPS4Downloader.cs | 41 ++++---- .../AbstractNeedsLoginDownloader.cs | 2 - .../Downloaders/BethesdaNetDownloader.cs | 98 ++++++++++--------- .../Downloaders/DeadlyStreamDownloader.cs | 1 + .../Downloaders/DownloadDispatcher.cs | 5 +- .../Downloaders/DropboxDownloader.cs | 10 +- .../Downloaders/GameFileSourceDownloader.cs | 25 +++-- .../Downloaders/GoogleDriveDownloader.cs | 21 ++-- Wabbajack.Lib/Downloaders/HTTPDownloader.cs | 48 ++++----- Wabbajack.Lib/Downloaders/IDownloader.cs | 4 +- Wabbajack.Lib/Downloaders/INeedsLogin.cs | 3 +- .../Downloaders/LoversLabDownloader.cs | 1 + Wabbajack.Lib/Downloaders/MEGADownloader.cs | 14 ++- Wabbajack.Lib/Downloaders/ManualDownloader.cs | 26 +++-- .../Downloaders/MediaFireDownloader.cs | 30 +++--- Wabbajack.Lib/Downloaders/ModDBDownloader.cs | 21 ++-- Wabbajack.Lib/Downloaders/NexusDownloader.cs | 24 +++-- .../Downloaders/TESAllianceDownloader.cs | 1 + .../Downloaders/VectorPlexusDownloader.cs | 1 + .../Downloaders/YouTubeDownloader.cs | 22 +++-- .../ContentRightsManagementTests.cs | 8 +- Wabbajack.Test/RestartingDownloadsTests.cs | 8 +- 29 files changed, 234 insertions(+), 226 deletions(-) diff --git a/Wabbajack.BuildServer.Test/ModListValidationTests.cs b/Wabbajack.BuildServer.Test/ModListValidationTests.cs index 4ea16eb0..434cc824 100644 --- a/Wabbajack.BuildServer.Test/ModListValidationTests.cs +++ b/Wabbajack.BuildServer.Test/ModListValidationTests.cs @@ -130,7 +130,7 @@ namespace Wabbajack.BuildServer.Test Hash = await test_archive_path.FileHashAsync(), Name = "test_archive", Size = test_archive_path.Size, - State = new HTTPDownloader.State {Url = MakeURL("test_archive.txt")} + State = new HTTPDownloader.State(MakeURL("test_archive.txt")) } } }; diff --git a/Wabbajack.BuildServer.Test/ModlistUpdater.cs b/Wabbajack.BuildServer.Test/ModlistUpdater.cs index 3295ea96..e7d62c15 100644 --- a/Wabbajack.BuildServer.Test/ModlistUpdater.cs +++ b/Wabbajack.BuildServer.Test/ModlistUpdater.cs @@ -45,10 +45,7 @@ namespace Wabbajack.BuildServer.Test Archive = new Archive { Name = "Oldfile", - State = new HTTPDownloader.State - { - Url = MakeURL("old_file_data.random"), - } + State = new HTTPDownloader.State(MakeURL("old_file_data.random")) } } }); @@ -60,10 +57,7 @@ namespace Wabbajack.BuildServer.Test Archive = new Archive { Name = "Newfile", - State = new HTTPDownloader.State - { - Url = MakeURL("new_file_data.random"), - } + State = new HTTPDownloader.State(MakeURL("new_file_data.random")) } } }); diff --git a/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs b/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs index c1983081..7f42cf04 100644 --- a/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs +++ b/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs @@ -22,10 +22,9 @@ namespace Wabbajack.BuildServer.Models.Jobs var states = GameRegistry.Games.Values .Where(game => game.GameLocation() != null && game.MainExecutable != null) .SelectMany(game => game.GameLocation().EnumerateFiles() - .Select(file => new GameFileSourceDownloader.State + .Select(file => new GameFileSourceDownloader.State(game.InstalledVersion) { Game = game.Game, - GameVersion = game.InstalledVersion, GameFile = file.RelativeTo(game.GameLocation()), })) .ToList(); @@ -59,11 +58,10 @@ namespace Wabbajack.BuildServer.Models.Jobs .ToList(); foreach (var job in jobs) - await sql.EnqueueJob(job); + await sql.EnqueueJob(job); return JobResult.Success(); } - } } } diff --git a/Wabbajack.BuildServer/Models/Jobs/IndexDynDOLOD.cs b/Wabbajack.BuildServer/Models/Jobs/IndexDynDOLOD.cs index 983d2d47..20353260 100644 --- a/Wabbajack.BuildServer/Models/Jobs/IndexDynDOLOD.cs +++ b/Wabbajack.BuildServer/Models/Jobs/IndexDynDOLOD.cs @@ -41,10 +41,7 @@ namespace Wabbajack.BuildServer.Models.Jobs Archive = new Archive { Name = Guid.NewGuid() + ".7z", - State = new MegaDownloader.State - { - Url = url.ToString() - } + State = new MegaDownloader.State(url.ToString()) } } }) diff --git a/Wabbajack.BuildServer/Models/Jobs/UploadToCDN.cs b/Wabbajack.BuildServer/Models/Jobs/UploadToCDN.cs index ff7d9619..1b9fa398 100644 --- a/Wabbajack.BuildServer/Models/Jobs/UploadToCDN.cs +++ b/Wabbajack.BuildServer/Models/Jobs/UploadToCDN.cs @@ -61,10 +61,7 @@ namespace Wabbajack.BuildServer.Models.Jobs Name = file.MungedName, Size = file.Size, Hash = file.Hash, - State = new HTTPDownloader.State - { - Url = file.Uri - } + State = new HTTPDownloader.State(file.Uri) } } }); diff --git a/Wabbajack.Lib/Downloaders/AFKModsDownloader.cs b/Wabbajack.Lib/Downloaders/AFKModsDownloader.cs index fdeb1385..62f84da3 100644 --- a/Wabbajack.Lib/Downloaders/AFKModsDownloader.cs +++ b/Wabbajack.Lib/Downloaders/AFKModsDownloader.cs @@ -1,4 +1,5 @@ using System; +#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs index a744ed97..196934d7 100644 --- a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs +++ b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs @@ -5,25 +5,25 @@ using System.Threading.Tasks; using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Lib.Validation; +#nullable enable namespace Wabbajack.Lib.Downloaders { public interface IMetaState { Uri URL { get; } - string Name { get; set; } - string Author { get; set; } - string Version { get; set; } - string ImageURL { get; set; } + string? Name { get; set; } + string? Author { get; set; } + string? Version { get; set; } + string? ImageURL { get; set; } bool IsNSFW { get; set; } - string Description { get; set; } + string? Description { get; set; } Task LoadMetaData(); } public abstract class AbstractDownloadState { - public static List KnownSubTypes = new List { typeof(HTTPDownloader.State), @@ -48,7 +48,7 @@ namespace Wabbajack.Lib.Downloaders static AbstractDownloadState() { - NameToType = KnownSubTypes.ToDictionary(t => t.FullName.Substring(t.Namespace.Length + 1), t => t); + NameToType = KnownSubTypes.ToDictionary(t => t.FullName!.Substring(t.Namespace!.Length + 1), t => t); TypeToName = NameToType.ToDictionary(k => k.Value, k => k.Key); } @@ -68,7 +68,6 @@ namespace Wabbajack.Lib.Downloaders } } - /// /// Returns true if this file is allowed to be downloaded via whitelist /// @@ -96,7 +95,7 @@ namespace Wabbajack.Lib.Downloaders public abstract IDownloader GetDownloader(); - public abstract string GetManifestURL(Archive a); + public abstract string? GetManifestURL(Archive a); public abstract string[] GetMetaIni(); } } diff --git a/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs b/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs index 67f0f498..5bff0424 100644 --- a/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs +++ b/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs @@ -8,6 +8,7 @@ using System.Web; using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Lib.Validation; +#nullable enable namespace Wabbajack.Lib.Downloaders { @@ -18,10 +19,12 @@ namespace Wabbajack.Lib.Downloaders where TState : AbstractIPS4Downloader.State, new() where TDownloader : IDownloader { - public override string SiteName { get; } - public override Uri SiteURL { get; } + protected AbstractIPS4Downloader(Uri loginUri, string encryptedKeyName, string cookieDomain) + : base(loginUri, encryptedKeyName, cookieDomain, "ips4_member_id") + { + } - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { Uri url = DownloaderUtils.GetDirectURL(archiveINI); @@ -70,23 +73,23 @@ namespace Wabbajack.Lib.Downloaders }; } - - public class State : AbstractDownloadState, IMetaState where TStateDownloader : IDownloader + public class State : AbstractDownloadState, IMetaState + where TStateDownloader : IDownloader { - public string FullURL { get; set; } + public string FullURL { get; set; } = string.Empty; public bool IsAttachment { get; set; } - public string FileID { get; set; } - - public string FileName { get; set; } + public string FileID { get; set; } = string.Empty; + + public string FileName { get; set; } = string.Empty; // from IMetaState public Uri URL => new Uri($"{Site}/files/file/{FileName}"); - public string Name { get; set; } - public string Author { get; set; } - public string Version { get; set; } - public string ImageURL { get; set; } + public string? Name { get; set; } + public string? Author { get; set; } + public string? Version { get; set; } + public string? ImageURL { get; set; } public virtual bool IsNSFW { get; set; } - public string Description { get; set; } + public string? Description { get; set; } private static bool IsHTTPS => Downloader.SiteURL.AbsolutePath.StartsWith("https://"); private static string URLPrefix => IsHTTPS ? "https://" : "http://"; @@ -119,6 +122,7 @@ namespace Wabbajack.Lib.Downloaders public override async Task Download(Archive a, AbsolutePath destination) { await using var stream = await ResolveDownloadStream(); + if (stream == null) return false; await using (var file = destination.Create()) { await stream.CopyToAsync(file); @@ -126,7 +130,7 @@ namespace Wabbajack.Lib.Downloaders return true; } - private async Task ResolveDownloadStream() + private async Task ResolveDownloadStream() { TOP: string url; @@ -236,12 +240,5 @@ namespace Wabbajack.Lib.Downloaders return false; } } - - 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 601b653f..e256b1b4 100644 --- a/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs +++ b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs @@ -138,6 +138,4 @@ namespace Wabbajack.Lib.Downloaders } } } - - } diff --git a/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs b/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs index 879b1025..8ca7a9f3 100644 --- a/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs +++ b/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs @@ -24,12 +24,22 @@ using Wabbajack.Lib.Validation; using File = Alphaleonis.Win32.Filesystem.File; using Game = Wabbajack.Common.Game; using Path = Alphaleonis.Win32.Filesystem.Path; +#nullable enable namespace Wabbajack.Lib.Downloaders { public class BethesdaNetDownloader : IUrlDownloader, INeedsLogin { public const string DataName = "bethesda-net-data"; + + public ReactiveCommand TriggerLogin { get; } + public ReactiveCommand ClearLogin { get; } + public IObservable IsLoggedIn => Utils.HaveEncryptedJsonObservable(DataName); + public string SiteName => "Bethesda.NET"; + public IObservable MetaInfo => Observable.Return(""); //"Wabbajack will start the game, then exit once you enter the Mods page"; + public Uri SiteURL => new Uri("https://bethesda.net"); + public Uri? IconUri { get; } + public BethesdaNetDownloader() { TriggerLogin = ReactiveCommand.CreateFromTask(() => Utils.CatchAndLog(RequestLoginAndCache), IsLoggedIn.Select(b => !b).ObserveOn(RxApp.MainThreadScheduler)); @@ -38,23 +48,23 @@ namespace Wabbajack.Lib.Downloaders private static async Task RequestLoginAndCache() { - var result = await Utils.Log(new RequestBethesdaNetLogin()).Task; + await Utils.Log(new RequestBethesdaNetLogin()).Task; } - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { var url = (Uri)DownloaderUtils.GetDirectURL(archiveINI); return StateFromUrl(url); } - internal static AbstractDownloadState StateFromUrl(Uri url) + internal static AbstractDownloadState? StateFromUrl(Uri url) { if (url != null && url.Host == "bethesda.net" && url.AbsolutePath.StartsWith("/en/mods/")) { var split = url.AbsolutePath.Split('/'); var game = split[3]; var modId = split[5]; - return new State {GameName = game, ContentId = modId}; + return new State(gameName: game, contentId: modId); } return null; } @@ -65,9 +75,10 @@ namespace Wabbajack.Lib.Downloaders await Utils.Log(new RequestBethesdaNetLogin()).Task; } - public static async Task Login(Game game) + public static async Task Login(Game game) { var metadata = game.MetaData(); + if (metadata.MainExecutable == null) throw new NotImplementedException(); var gamePath = metadata.GameLocation().Combine(metadata.MainExecutable); var info = new ProcessStartInfo { @@ -102,28 +113,25 @@ namespace Wabbajack.Lib.Downloaders } } - public AbstractDownloadState GetDownloaderState(string url) + public AbstractDownloadState? GetDownloaderState(string url) { return StateFromUrl(new Uri(url)); } - public ReactiveCommand TriggerLogin { get; } - public ReactiveCommand ClearLogin { get; } - public IObservable IsLoggedIn => Utils.HaveEncryptedJsonObservable(DataName); - public string SiteName => "Bethesda.NET"; - public IObservable MetaInfo => Observable.Return(""); //"Wabbajack will start the game, then exit once you enter the Mods page"; - public Uri SiteURL => new Uri("https://bethesda.net"); - public Uri IconUri { get; } - - [JsonName("BethesdaNetDownloader")] public class State : AbstractDownloadState { - public string GameName { get; set; } - public string ContentId { get; set; } - + public string GameName { get; } + public string ContentId { get; } + [JsonIgnore] - public override object[] PrimaryKey => new object[] {GameName, ContentId}; + public override object[] PrimaryKey => new object[] { GameName, ContentId }; + + public State(string gameName, string contentId) + { + GameName = gameName; + ContentId = contentId; + } public override bool IsWhitelisted(ServerWhitelist whitelist) { @@ -142,8 +150,8 @@ namespace Wabbajack.Lib.Downloaders using var got = await client.GetAsync( $"https://content.cdp.bethesda.net/{collected.CDPProductId}/{collected.CDPPropertiesId}/{chunk.sha}"); var data = await got.Content.ReadAsByteArrayAsync(); - if (collected.AESKey != null) - AESCTRDecrypt(collected.AESKey, collected.AESIV, data); + if (collected.AESKey != null) + AESCTRDecrypt(collected.AESKey, collected.AESIV!, data); if (chunk.uncompressed_size == chunk.chunk_size) await file.WriteAsync(data, 0, data.Length); @@ -197,7 +205,7 @@ namespace Wabbajack.Lib.Downloaders public override async Task Verify(Archive archive) { - var info = await ResolveDownloadInfo(); + await ResolveDownloadInfo(); return true; } @@ -221,7 +229,7 @@ namespace Wabbajack.Lib.Downloaders client.Headers.Add(("x-cdp-app", "UGC SDK")); client.Headers.Add(("x-cdp-app-ver", "0.9.11314/debug")); client.Headers.Add(("x-cdp-lib-ver", "0.9.11314/debug")); - client.Headers.Add(("x-cdp-platform","Win/32")); + client.Headers.Add(("x-cdp-platform", "Win/32")); posted = await client.PostAsync("https://api.bethesda.net/cdp-user/auth", new StringContent("{\"access_token\": \"" + info.AccessToken + "\"}", Encoding.UTF8, @@ -232,10 +240,10 @@ namespace Wabbajack.Lib.Downloaders var got = await client.GetAsync($"https://api.bethesda.net/mods/ugc-workshop/content/get?content_id={ContentId}"); JObject data = JObject.Parse(await got.Content.ReadAsStringAsync()); - var content = data["platform"]["response"]["content"]; + var content = data["platform"]!["response"]!["content"]!; - info.CDPBranchId = (int)content["cdp_branch_id"]; - info.CDPProductId = (int)content["cdp_product_id"]; + info.CDPBranchId = (int)content["cdp_branch_id"]!; + info.CDPProductId = (int)content["cdp_product_id"]!; client.Headers.Add(("Authorization", $"Token {info.CDPToken}")); client.Headers.Add(("Accept", "application/json")); @@ -245,7 +253,7 @@ namespace Wabbajack.Lib.Downloaders $"https://api.bethesda.net/cdp-user/projects/{info.CDPProductId}/branches/{info.CDPBranchId}/tree/.json"); var tree = (await got.Content.ReadAsStringAsync()).FromJsonString(); - + got.Dispose(); got = await client.PostAsync($"https://api.bethesda.net/mods/ugc-content/add-subscription", new StringContent($"{{\"content_id\": \"{ContentId}\"}}", Encoding.UTF8, "application/json")); @@ -254,14 +262,14 @@ namespace Wabbajack.Lib.Downloaders $"https://api.bethesda.net/cdp-user/projects/{info.CDPProductId}/branches/{info.CDPBranchId}/depots/.json"); var props_obj = JObject.Parse(await got.Content.ReadAsStringAsync()).Properties().First(); - info.CDPPropertiesId = (int)props_obj.Value["properties_id"]; - + info.CDPPropertiesId = (int)props_obj.Value["properties_id"]!; + info.AESKey = props_obj.Value["ex_info_A"].Select(e => (byte)e).ToArray(); info.AESIV = props_obj.Value["ex_info_B"].Select(e => (byte)e).Take(16).ToArray(); return (client, tree, info); } - + static int AESCTRDecrypt(byte[] Key, byte[] IV, byte[] Data) { IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding"); @@ -282,27 +290,26 @@ namespace Wabbajack.Lib.Downloaders public override string[] GetMetaIni() { - return new[] {"[General]", $"directURL=https://bethesda.net/en/mods/{GameName}/mod-detail/{ContentId}"}; + return new[] { "[General]", $"directURL=https://bethesda.net/en/mods/{GameName}/mod-detail/{ContentId}" }; } private class BeamLoginResponse { - public string access_token { get; set; } - + public string access_token { get; set; } = string.Empty; } private class CDPLoginResponse { - public string token { get; set; } + public string token { get; set; } = string.Empty; } private class CollectedBNetInfo { - public byte[] AESKey { get; set; } - public byte[] AESIV { get; set; } - public string AccessToken { get; set; } - public string CDPToken { get; set; } + public byte[] AESKey { get; set; } = null!; + public byte[] AESIV { get; set; } = null!; + public string AccessToken { get; set; } = string.Empty; + public string CDPToken { get; set; } = string.Empty; public int CDPBranchId { get; set; } public int CDPProductId { get; set; } public int CDPPropertiesId { get; set; } @@ -310,24 +317,24 @@ namespace Wabbajack.Lib.Downloaders public class CDPTree { - public List depot_list { get; set; } + public List depot_list { get; set; } = null!; public class Depot { - public List file_list { get; set; } + public List file_list { get; set; } = null!; public class CDPFile { public int chunk_count { get; set; } - public List chunk_list { get; set; } + public List chunk_list { get; set; } = null!; - public string name { get; set; } + public string? name { get; set; } public class Chunk { public int chunk_size { get; set; } public int index { get; set; } - public string sha { get; set; } + public string sha { get; set; } = string.Empty; public int uncompressed_size { get; set; } } } @@ -344,7 +351,7 @@ namespace Wabbajack.Lib.Downloaders public class RequestBethesdaNetLogin : AUserIntervention { public override string ShortDescription => "Logging into Bethesda.NET"; - public override string ExtendedDescription { get; } + public override string ExtendedDescription { get; } = string.Empty; private readonly TaskCompletionSource _source = new TaskCompletionSource(); public Task Task => _source.Task; @@ -365,8 +372,7 @@ namespace Wabbajack.Lib.Downloaders public class BethesdaNetData { - public string body { get; set; } + public string body { get; set; } = string.Empty; public Dictionary headers = new Dictionary(); } - } diff --git a/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs b/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs index 2da650c1..a1131998 100644 --- a/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs +++ b/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs @@ -1,4 +1,5 @@ using System; +#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs b/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs index 645c1f9f..7bdb271a 100644 --- a/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs +++ b/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs @@ -115,10 +115,7 @@ namespace Wabbajack.Lib.Downloaders var patchState = new Archive { Name = patchName, - State = new HTTPDownloader.State - { - Url = $"https://wabbajackcdn.b-cdn.net/updates/{patchName}" - } + State = new HTTPDownloader.State($"https://wabbajackcdn.b-cdn.net/updates/{patchName}") }; var patchResult = await Download(patchState, patchPath); diff --git a/Wabbajack.Lib/Downloaders/DropboxDownloader.cs b/Wabbajack.Lib/Downloaders/DropboxDownloader.cs index 6a2da893..270b4299 100644 --- a/Wabbajack.Lib/Downloaders/DropboxDownloader.cs +++ b/Wabbajack.Lib/Downloaders/DropboxDownloader.cs @@ -2,18 +2,19 @@ using System.Threading.Tasks; using System.Web; using Wabbajack.Common; +#nullable enable namespace Wabbajack.Lib.Downloaders { public class DropboxDownloader : IDownloader, IUrlDownloader { - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { var urlstring = archiveINI?.General?.directURL; return GetDownloaderState(urlstring); } - public AbstractDownloadState GetDownloaderState(string url) + public AbstractDownloadState? GetDownloaderState(string url) { try { @@ -29,10 +30,7 @@ namespace Wabbajack.Lib.Downloaders uri.Query = query.ToString(); - return new HTTPDownloader.State() - { - Url = uri.ToString().Replace("dropbox.com:443/", "dropbox.com/") - }; + return new HTTPDownloader.State(uri.ToString().Replace("dropbox.com:443/", "dropbox.com/")); } catch (Exception) { diff --git a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs index dd351330..b4b2ace7 100644 --- a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs @@ -4,17 +4,18 @@ using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Validation; using Game = Wabbajack.Common.Game; +#nullable enable namespace Wabbajack.Lib.Downloaders { public class GameFileSourceDownloader : IDownloader { - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { - var gameName = (string)archiveINI?.General?.gameName; - var gameFile = (string)archiveINI?.General?.gameFile; + var gameName = (string?)archiveINI?.General?.gameName; + var gameFile = (string?)archiveINI?.General?.gameFile; - if (gameFile == null || gameFile == null) + if (gameName == null || gameFile == null) return null; var game = GameRegistry.GetByFuzzyName(gameName); @@ -23,18 +24,17 @@ namespace Wabbajack.Lib.Downloaders var path = game.TryGetGameLocation(); var filePath = path?.Combine(gameFile); - if (!filePath?.Exists ?? false) + if (!(filePath?.Exists ?? false)) return null; var fp = filePath.Value; var hash = await fp.FileHashCachedAsync(); - return new State + return new State(game.InstalledVersion) { Game = game.Game, GameFile = (RelativePath)gameFile, - Hash = hash, - GameVersion = game.InstalledVersion + Hash = hash }; } @@ -48,7 +48,12 @@ namespace Wabbajack.Lib.Downloaders public Game Game { get; set; } public RelativePath GameFile { get; set; } public Hash Hash { get; set; } - public string GameVersion { get; set; } + public string GameVersion { get; } + + public State(string gameVersion) + { + GameVersion = gameVersion; + } [JsonIgnore] internal AbsolutePath SourcePath => Game.MetaData().GameLocation().Combine(GameFile); @@ -81,7 +86,7 @@ namespace Wabbajack.Lib.Downloaders return DownloadDispatcher.GetInstance(); } - public override string GetManifestURL(Archive a) + public override string? GetManifestURL(Archive a) { return null; } diff --git a/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs b/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs index 9c96e219..db385314 100644 --- a/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs @@ -5,27 +5,25 @@ using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Exceptions; using Wabbajack.Lib.Validation; +#nullable enable namespace Wabbajack.Lib.Downloaders { public class GoogleDriveDownloader : IDownloader, IUrlDownloader { - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { var url = archiveINI?.General?.directURL; return GetDownloaderState(url); } - public AbstractDownloadState GetDownloaderState(string url) + public AbstractDownloadState? GetDownloaderState(string url) { if (url != null && url.StartsWith("https://drive.google.com")) { var regex = new Regex("((?<=id=)[a-zA-Z0-9_-]*)|(?<=\\/file\\/d\\/)[a-zA-Z0-9_-]*"); var match = regex.Match(url); - return new State - { - Id = match.ToString() - }; + return new State(match.ToString()); } return null; @@ -38,10 +36,15 @@ namespace Wabbajack.Lib.Downloaders [JsonName("GoogleDriveDownloader")] public class State : AbstractDownloadState { - public string Id { get; set; } + public string Id { get; } [JsonIgnore] - public override object[] PrimaryKey { get => new object[] {Id}; } + public override object[] PrimaryKey => new object[] { Id }; + + public State(string id) + { + Id = id; + } public override bool IsWhitelisted(ServerWhitelist whitelist) { @@ -64,7 +67,7 @@ namespace Wabbajack.Lib.Downloaders var regex = new Regex("(?<=/uc\\?export=download&confirm=).*(?=;id=)"); var confirm = regex.Match(await response.Content.ReadAsStringAsync()); var url = $"https://drive.google.com/uc?export=download&confirm={confirm}&id={Id}"; - var httpState = new HTTPDownloader.State {Url = url, Client = client}; + var httpState = new HTTPDownloader.State(url) { Client = client }; return httpState; } diff --git a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs index 9b051f38..12455dca 100644 --- a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs +++ b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs @@ -10,34 +10,30 @@ using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Exceptions; using Wabbajack.Lib.Validation; +#nullable enable namespace Wabbajack.Lib.Downloaders { public class HTTPDownloader : IDownloader, IUrlDownloader { - - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { var url = archiveINI?.General?.directURL; return GetDownloaderState(url, archiveINI); } - public AbstractDownloadState GetDownloaderState(string uri) + public AbstractDownloadState? GetDownloaderState(string uri) { return GetDownloaderState(uri, null); } - public AbstractDownloadState GetDownloaderState(string url, dynamic archiveINI) + public AbstractDownloadState? GetDownloaderState(string url, dynamic? archiveINI) { if (url != null) { - var tmp = new State - { - Url = url - }; + var tmp = new State(url); if (archiveINI?.General?.directURLHeaders != null) { - tmp.Headers = new List(); tmp.Headers.AddRange(archiveINI?.General.directURLHeaders.Split('|')); } return tmp; @@ -53,15 +49,20 @@ namespace Wabbajack.Lib.Downloaders [JsonName("HttpDownloader")] public class State : AbstractDownloadState { - public string Url { get; set; } + public string Url { get; } - public List Headers { get; set; } + public List Headers { get; } = new List(); [JsonIgnore] - public Common.Http.Client Client { get; set; } + public Common.Http.Client? Client { get; set; } [JsonIgnore] - public override object[] PrimaryKey { get => new object[] {Url};} + public override object[] PrimaryKey => new object[] { Url }; + + public State(string url) + { + Url = url; + } public override bool IsWhitelisted(ServerWhitelist whitelist) { @@ -85,19 +86,18 @@ namespace Wabbajack.Lib.Downloaders var client = Client ?? new Common.Http.Client(); client.Headers.Add(("User-Agent", Consts.UserAgent)); - if (Headers != null) - foreach (var header in Headers) - { - var idx = header.IndexOf(':'); - var k = header.Substring(0, idx); - var v = header.Substring(idx + 1); - client.Headers.Add((k, v)); - } + foreach (var header in Headers) + { + var idx = header.IndexOf(':'); + var k = header.Substring(0, idx); + var v = header.Substring(idx + 1); + client.Headers.Add((k, v)); + } long totalRead = 0; var bufferSize = 1024 * 32; - Utils.Status($"Starting Download {a?.Name ?? Url}", Percent.Zero); + Utils.Status($"Starting Download {a.Name ?? Url}", Percent.Zero); var response = await client.GetAsync(Url); TOP: @@ -177,7 +177,7 @@ TOP: if (read == 0) break; Utils.Status($"Downloading {a.Name}", Percent.FactoryPutInRange(totalRead, contentSize)); - fs.Write(buffer, 0, read); + fs!.Write(buffer, 0, read); totalRead += read; } } @@ -203,7 +203,7 @@ TOP: public override string[] GetMetaIni() { - if (Headers != null) + if (Headers.Count > 0) return new [] {"[General]", $"directURL={Url}", $"directURLHeaders={string.Join("|", Headers)}"}; diff --git a/Wabbajack.Lib/Downloaders/IDownloader.cs b/Wabbajack.Lib/Downloaders/IDownloader.cs index ddac3407..b43aef76 100644 --- a/Wabbajack.Lib/Downloaders/IDownloader.cs +++ b/Wabbajack.Lib/Downloaders/IDownloader.cs @@ -1,15 +1,15 @@ using System.Threading.Tasks; +#nullable enable namespace Wabbajack.Lib.Downloaders { public interface IDownloader { - Task GetDownloaderState(dynamic archiveINI, bool quickMode = false); + Task GetDownloaderState(dynamic archiveINI, bool quickMode = false); /// /// Called before any downloads are inacted by the installer; /// Task Prepare(); } - } diff --git a/Wabbajack.Lib/Downloaders/INeedsLogin.cs b/Wabbajack.Lib/Downloaders/INeedsLogin.cs index 6f331011..d22a6f05 100644 --- a/Wabbajack.Lib/Downloaders/INeedsLogin.cs +++ b/Wabbajack.Lib/Downloaders/INeedsLogin.cs @@ -2,6 +2,7 @@ using System.Reactive; using System.Security; using ReactiveUI; +#nullable enable namespace Wabbajack.Lib.Downloaders { @@ -13,7 +14,7 @@ namespace Wabbajack.Lib.Downloaders string SiteName { get; } IObservable MetaInfo { get; } Uri SiteURL { get; } - Uri IconUri { get; } + Uri? IconUri { get; } } public struct LoginReturnMessage diff --git a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs index c319fb7a..e1b7a06d 100644 --- a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs +++ b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.WebAutomation; +#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/MEGADownloader.cs b/Wabbajack.Lib/Downloaders/MEGADownloader.cs index e612c2c3..02977628 100644 --- a/Wabbajack.Lib/Downloaders/MEGADownloader.cs +++ b/Wabbajack.Lib/Downloaders/MEGADownloader.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json; using ReactiveUI; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; +#nullable enable namespace Wabbajack.Lib.Downloaders { @@ -23,8 +24,6 @@ namespace Wabbajack.Lib.Downloaders try { authInfos = MegaApiClient.GenerateAuthInfos(username, password.ToNormalString()); - username = null; - password = null; } catch (ApiException e) { @@ -72,16 +71,16 @@ namespace Wabbajack.Lib.Downloaders IsLoggedIn.ObserveOnGuiThread()); } - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { var url = archiveINI?.General?.directURL; return GetDownloaderState(url); } - public AbstractDownloadState GetDownloaderState(string url) + public AbstractDownloadState? GetDownloaderState(string url) { if (url != null && url.StartsWith(Consts.MegaPrefix)) - return new State { Url = url}; + return new State(url); return null; } @@ -92,6 +91,11 @@ namespace Wabbajack.Lib.Downloaders [JsonName("MegaDownloader")] public class State : HTTPDownloader.State { + public State(string url) + : base(url) + { + } + private static MegaApiClient MegaApiClient => DownloadDispatcher.GetInstance().MegaApiClient; private void MegaLogin() diff --git a/Wabbajack.Lib/Downloaders/ManualDownloader.cs b/Wabbajack.Lib/Downloaders/ManualDownloader.cs index f08fe587..b9f4ba72 100644 --- a/Wabbajack.Lib/Downloaders/ManualDownloader.cs +++ b/Wabbajack.Lib/Downloaders/ManualDownloader.cs @@ -6,6 +6,7 @@ using Wabbajack.Common; using Wabbajack.Common.IO; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Validation; +#nullable enable namespace Wabbajack.Lib.Downloaders { @@ -18,8 +19,8 @@ namespace Wabbajack.Lib.Downloaders class FileEvent { - public string FullPath { get; set; } - public string Name { get; set; } + public string FullPath { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; public long Size { get; set; } } @@ -57,10 +58,10 @@ namespace Wabbajack.Lib.Downloaders } } - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { var url = archiveINI?.General?.manualURL; - return url != null ? new State { Url = url} : null; + return url != null ? new State(url) : null; } public async Task Prepare() @@ -70,10 +71,15 @@ namespace Wabbajack.Lib.Downloaders [JsonName("ManualDownloader")] public class State : AbstractDownloadState { - public string Url { get; set; } + public string Url { get; } [JsonIgnore] - public override object[] PrimaryKey { get => new object[] {Url}; } + public override object[] PrimaryKey => new object[] { Url }; + + public State(string url) + { + Url = url; + } public override bool IsWhitelisted(ServerWhitelist whitelist) { @@ -83,7 +89,7 @@ namespace Wabbajack.Lib.Downloaders public override async Task Download(Archive a, AbsolutePath destination) { var (uri, client) = await Utils.Log(await ManuallyDownloadFile.Create(this)).Task; - var state = new HTTPDownloader.State {Url = uri.ToString(), Client = client}; + var state = new HTTPDownloader.State(uri.ToString()) { Client = client }; return await state.Download(a, destination); } @@ -104,10 +110,10 @@ namespace Wabbajack.Lib.Downloaders public override string[] GetMetaIni() { - return new [] { + return new [] + { "[General]", - $"manualURL={Url}" - + $"manualURL={Url}", }; } } diff --git a/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs b/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs index 03e09d90..c895002a 100644 --- a/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs +++ b/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs @@ -5,27 +5,30 @@ using System.Threading.Tasks; using Wabbajack.Common; using Wabbajack.Lib.Validation; using Wabbajack.Lib.WebAutomation; +#nullable enable namespace Wabbajack.Lib.Downloaders { public class MediaFireDownloader : IUrlDownloader { - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { Uri url = DownloaderUtils.GetDirectURL(archiveINI); if (url == null || url.Host != "www.mediafire.com") return null; - return new State - { - Url = url.ToString() - }; + return new State(url.ToString()); } public class State : AbstractDownloadState { - public string Url { get; set; } + public string Url { get; } - public override object[] PrimaryKey { get => new object[] {Url};} + public override object[] PrimaryKey => new object[] { Url }; + + public State(string url) + { + Url = url; + } public override bool IsWhitelisted(ServerWhitelist whitelist) { @@ -35,6 +38,7 @@ namespace Wabbajack.Lib.Downloaders public override async Task Download(Archive a, AbsolutePath destination) { var result = await Resolve(); + if (result == null) return false; return await result.Download(a, destination); } @@ -43,7 +47,7 @@ namespace Wabbajack.Lib.Downloaders return await Resolve() != null; } - private async Task Resolve() + private async Task Resolve() { using (var d = await Driver.Create()) { @@ -52,10 +56,9 @@ namespace Wabbajack.Lib.Downloaders await Task.Delay(1000); var newURL = await d.GetAttr("a.input", "href"); if (newURL == null || !newURL.StartsWith("http")) return null; - return new HTTPDownloader.State() + return new HTTPDownloader.State(newURL) { Client = new Common.Http.Client(), - Url = newURL }; } } @@ -84,15 +87,12 @@ namespace Wabbajack.Lib.Downloaders { } - public AbstractDownloadState GetDownloaderState(string u) + public AbstractDownloadState? GetDownloaderState(string u) { var url = new Uri(u); if (url.Host != "www.mediafire.com") return null; - return new State - { - Url = url.ToString() - }; + return new State(url.ToString()); } } } diff --git a/Wabbajack.Lib/Downloaders/ModDBDownloader.cs b/Wabbajack.Lib/Downloaders/ModDBDownloader.cs index d48064ba..1a3b51fe 100644 --- a/Wabbajack.Lib/Downloaders/ModDBDownloader.cs +++ b/Wabbajack.Lib/Downloaders/ModDBDownloader.cs @@ -6,25 +6,23 @@ using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Validation; +#nullable enable namespace Wabbajack.Lib.Downloaders { public class ModDBDownloader : IDownloader, IUrlDownloader { - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { var url = archiveINI?.General?.directURL; return GetDownloaderState(url); } - public AbstractDownloadState GetDownloaderState(string url) + public AbstractDownloadState? GetDownloaderState(string url) { if (url != null && url.StartsWith("https://www.moddb.com/downloads/start")) { - return new State - { - Url = url - }; + return new State(url); } return null; @@ -37,10 +35,15 @@ namespace Wabbajack.Lib.Downloaders [JsonName("ModDBDownloader")] public class State : AbstractDownloadState { - public string Url { get; set; } + public string Url { get; } [JsonIgnore] - public override object[] PrimaryKey { get => new object[]{Url}; } + public override object[] PrimaryKey => new object[] { Url }; + + public State(string url) + { + Url = url; + } public override bool IsWhitelisted(ServerWhitelist whitelist) { @@ -56,7 +59,7 @@ namespace Wabbajack.Lib.Downloaders { try { - await new HTTPDownloader.State {Url = url}.Download(a, destination); + await new HTTPDownloader.State(url).Download(a, destination); return true; } catch (Exception) diff --git a/Wabbajack.Lib/Downloaders/NexusDownloader.cs b/Wabbajack.Lib/Downloaders/NexusDownloader.cs index 77942288..fc4728d3 100644 --- a/Wabbajack.Lib/Downloaders/NexusDownloader.cs +++ b/Wabbajack.Lib/Downloaders/NexusDownloader.cs @@ -12,6 +12,7 @@ using Wabbajack.Common.StatusFeed.Errors; using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.Validation; using Game = Wabbajack.Common.Game; +#nullable enable namespace Wabbajack.Lib.Downloaders { @@ -19,8 +20,8 @@ namespace Wabbajack.Lib.Downloaders { private bool _prepared; private AsyncLock _lock = new AsyncLock(); - private UserStatus _status; - private NexusApiClient _client; + private UserStatus? _status; + private NexusApiClient? _client; public IObservable IsLoggedIn => Utils.HaveEncryptedJsonObservable("nexusapikey"); @@ -50,9 +51,9 @@ namespace Wabbajack.Lib.Downloaders canExecute: IsLoggedIn.ObserveOnGuiThread()); } - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { - var general = archiveINI?.General; + var general = archiveINI.General; if (general.modID != null && general.fileID != null && general.gameName != null) { @@ -135,17 +136,17 @@ namespace Wabbajack.Lib.Downloaders [JsonIgnore] public Uri URL => new Uri($"http://nexusmods.com/{Game.MetaData().NexusName}/mods/{ModID}"); - public string Name { get; set; } + public string? Name { get; set; } - public string Author { get; set; } + public string? Author { get; set; } - public string Version { get; set; } + public string? Version { get; set; } - public string ImageURL { get; set; } + public string? ImageURL { get; set; } public bool IsNSFW { get; set; } - public string Description { get; set; } + public string? Description { get; set; } [JsonProperty("GameName")] [JsonConverter(typeof(Utils.GameConverter))] @@ -184,10 +185,7 @@ namespace Wabbajack.Lib.Downloaders Utils.Log($"Downloading Nexus Archive - {a.Name} - {Game} - {ModID} - {FileID}"); - return await new HTTPDownloader.State - { - Url = url - }.Download(a, destination); + return await new HTTPDownloader.State(url).Download(a, destination); } public override async Task Verify(Archive a) diff --git a/Wabbajack.Lib/Downloaders/TESAllianceDownloader.cs b/Wabbajack.Lib/Downloaders/TESAllianceDownloader.cs index ae6a8fa1..16cf46cc 100644 --- a/Wabbajack.Lib/Downloaders/TESAllianceDownloader.cs +++ b/Wabbajack.Lib/Downloaders/TESAllianceDownloader.cs @@ -1,6 +1,7 @@ using System; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; +#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs b/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs index 8f7d1c5c..f0cdafb8 100644 --- a/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs +++ b/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs @@ -1,5 +1,6 @@ using System; using Wabbajack.Common.Serialization.Json; +#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/YouTubeDownloader.cs b/Wabbajack.Lib/Downloaders/YouTubeDownloader.cs index c72184d0..4e6be90c 100644 --- a/Wabbajack.Lib/Downloaders/YouTubeDownloader.cs +++ b/Wabbajack.Lib/Downloaders/YouTubeDownloader.cs @@ -15,15 +15,16 @@ using YoutubeExplode.Exceptions; using YoutubeExplode.Models.MediaStreams; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; +#nullable enable namespace Wabbajack.Lib.Downloaders { public class YouTubeDownloader : IDownloader { - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { var directURL = (Uri)DownloaderUtils.GetDirectURL(archiveINI); - var state = (State)UriToState(directURL); + var state = UriToState(directURL) as State; if (state == null) return state; var idx = 0; @@ -44,7 +45,7 @@ namespace Wabbajack.Lib.Downloaders return state; } - internal static AbstractDownloadState UriToState(Uri directURL) + internal static AbstractDownloadState? UriToState(Uri directURL) { if (directURL == null || !directURL.Host.EndsWith("youtube.com")) { @@ -52,7 +53,7 @@ namespace Wabbajack.Lib.Downloaders } var key = HttpUtility.ParseQueryString(directURL.Query)["v"]; - return key != null ? new State {Key = key} : null; + return key != null ? new State(key) : null; } public async Task Prepare() @@ -62,13 +63,18 @@ namespace Wabbajack.Lib.Downloaders [JsonName("YouTubeDownloader")] public class State : AbstractDownloadState { - public string Key { get; set; } + public string Key { get; } public List Tracks { get; set; } = new List(); [JsonIgnore] public override object[] PrimaryKey => new object[] {Key}; + public State(string key) + { + Key = key; + } + [JsonName("YouTubeTrack")] public class Track { @@ -78,8 +84,8 @@ namespace Wabbajack.Lib.Downloaders WAV } public FormatEnum Format { get; set; } - - public string Name { get; set; } + + public string Name { get; set; } = string.Empty; public TimeSpan Start { get; set; } @@ -164,7 +170,7 @@ namespace Wabbajack.Lib.Downloaders p.Start(); ChildProcessTracker.AddProcess(p); - var output = await p.StandardError.ReadToEndAsync(); + await p.StandardError.ReadToEndAsync(); try { diff --git a/Wabbajack.Test/ContentRightsManagementTests.cs b/Wabbajack.Test/ContentRightsManagementTests.cs index 4c9b1eb6..0d915da4 100644 --- a/Wabbajack.Test/ContentRightsManagementTests.cs +++ b/Wabbajack.Test/ContentRightsManagementTests.cs @@ -73,7 +73,7 @@ namespace Wabbajack.Test modlist.GameType = Game.Skyrim; modlist.Archives[0] = new Archive() { - State = new HTTPDownloader.State() { Url = "https://somebadplace.com" }, + State = new HTTPDownloader.State("https://somebadplace.com"), Hash = Hash.FromLong(42) }; var errors = await validate.Validate(modlist); @@ -83,7 +83,7 @@ namespace Wabbajack.Test modlist.GameType = Game.Skyrim; modlist.Archives[0] = new Archive { - State = new HTTPDownloader.State { Url = "https://somegoodplace.com/baz.7z" }, + State = new HTTPDownloader.State("https://somegoodplace.com/baz.7z"), Hash = Hash.FromLong(42) }; errors = await validate.Validate(modlist); @@ -94,7 +94,7 @@ namespace Wabbajack.Test modlist.GameType = Game.Skyrim; modlist.Archives[0] = new Archive { - State = new GoogleDriveDownloader.State { Id = "bleg"}, + State = new GoogleDriveDownloader.State("bleg"), Hash = Hash.FromLong(42) }; errors = await validate.Validate(modlist); @@ -104,7 +104,7 @@ namespace Wabbajack.Test modlist.GameType = Game.Skyrim; modlist.Archives[0] = new Archive { - State = new GoogleDriveDownloader.State { Id = "googleDEADBEEF" }, + State = new GoogleDriveDownloader.State("googleDEADBEEF"), Hash = Hash.FromLong(42) }; errors = await validate.Validate(modlist); diff --git a/Wabbajack.Test/RestartingDownloadsTests.cs b/Wabbajack.Test/RestartingDownloadsTests.cs index c93e3a6c..d8602d76 100644 --- a/Wabbajack.Test/RestartingDownloadsTests.cs +++ b/Wabbajack.Test/RestartingDownloadsTests.cs @@ -72,8 +72,8 @@ namespace Wabbajack.Test { using var testFile = new TempFile(); using var server = new CrappyRandomServer(); - var state = new HTTPDownloader.State {Url = $"http://localhost:{server.Port}/foo"}; - + var state = new HTTPDownloader.State($"http://localhost:{server.Port}/foo"); + await state.Download(testFile.Path); Assert.Equal(server.Data, await testFile.Path.ReadAllBytesAsync()); @@ -87,8 +87,4 @@ namespace Wabbajack.Test _unsubIntevention?.Dispose(); } } - - - - } From 4e1a32caac37ee7b1160b3ca628b6491f8dbd5be Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 16:05:07 -0500 Subject: [PATCH 09/23] MO2Compiler nullability enabled --- Wabbajack.Common/Extensions/DictionaryExt.cs | 16 +++++ Wabbajack.Common/Extensions/EnumerableExt.cs | 27 ++++++++ Wabbajack.Common/Extensions/ListExt.cs | 15 +++++ Wabbajack.Lib/ACompiler.cs | 8 +-- Wabbajack.Lib/MO2Compiler.cs | 68 +++++++++----------- 5 files changed, 91 insertions(+), 43 deletions(-) create mode 100644 Wabbajack.Common/Extensions/ListExt.cs diff --git a/Wabbajack.Common/Extensions/DictionaryExt.cs b/Wabbajack.Common/Extensions/DictionaryExt.cs index 64ea3f03..89af60a1 100644 --- a/Wabbajack.Common/Extensions/DictionaryExt.cs +++ b/Wabbajack.Common/Extensions/DictionaryExt.cs @@ -21,6 +21,9 @@ namespace Wabbajack return ret; } + /// + /// Adds the given values to the dictionary. If a key already exists, it will throw an exception + /// public static void Add(this IDictionary dict, IEnumerable> vals) where K : notnull { @@ -30,6 +33,9 @@ namespace Wabbajack } } + /// + /// Adds the given values to the dictionary. If a key already exists, it will be replaced + /// public static void Set(this IDictionary dict, IEnumerable> vals) where K : notnull { @@ -38,5 +44,15 @@ namespace Wabbajack dict[val.Key] = val.Value; } } + + /// + /// Clears the dictionary and adds the given values + /// + public static void SetTo(this IDictionary dict, IEnumerable> vals) + where K : notnull + { + dict.Clear(); + dict.Set(vals); + } } } diff --git a/Wabbajack.Common/Extensions/EnumerableExt.cs b/Wabbajack.Common/Extensions/EnumerableExt.cs index e93b6c03..50dfb778 100644 --- a/Wabbajack.Common/Extensions/EnumerableExt.cs +++ b/Wabbajack.Common/Extensions/EnumerableExt.cs @@ -33,5 +33,32 @@ namespace Wabbajack yield return next; foreach (var itm in coll) yield return itm; } + + /// + /// Converts and filters a nullable enumerable to a non-nullable enumerable + /// + public static IEnumerable NotNull(this IEnumerable e) + where T : class + { + // Filter out nulls + return e.Where(e => e != null) + // Cast to non nullable type + .Select(e => e!); + } + + /// + /// Selects items that are castable to the desired type + /// + /// Type of the original enumerable to cast from + /// Type to attempt casting to + /// Enumerable to process + /// Enumerable with only objects that were castable + public static IEnumerable WhereCastable(this IEnumerable e) + where T : class + where R : T + { + return e.Where(e => e is R) + .Select(e => (R)e); + } } } diff --git a/Wabbajack.Common/Extensions/ListExt.cs b/Wabbajack.Common/Extensions/ListExt.cs new file mode 100644 index 00000000..0aa872c5 --- /dev/null +++ b/Wabbajack.Common/Extensions/ListExt.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Wabbajack.Common +{ + public static class ListExt + { + public static void SetTo(this List list, IEnumerable rhs) + { + list.Clear(); + list.AddRange(rhs); + } + } +} diff --git a/Wabbajack.Lib/ACompiler.cs b/Wabbajack.Lib/ACompiler.cs index aa036ddd..ef5490eb 100644 --- a/Wabbajack.Lib/ACompiler.cs +++ b/Wabbajack.Lib/ACompiler.cs @@ -43,9 +43,9 @@ namespace Wabbajack.Lib public bool IgnoreMissingFiles { get; set; } - public ICollection SelectedArchives = new List(); - public List InstallDirectives = new List(); - public List AllFiles = new List(); + public readonly List SelectedArchives = new List(); + public readonly List InstallDirectives = new List(); + public readonly List AllFiles = new List(); public ModList ModList = new ModList(); public List IndexedArchives = new List(); @@ -222,7 +222,7 @@ namespace Wabbajack.Lib .GroupBy(f => f.File.Hash) .ToDictionary(f => f.Key, f => f.First()); - SelectedArchives = await hashes.PMap(Queue, hash => ResolveArchive(hash, archives)); + SelectedArchives.SetTo(await hashes.PMap(Queue, hash => ResolveArchive(hash, archives))); } public async Task ResolveArchive(Hash hash, IDictionary archives) diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 1f9ea5a1..79181eaa 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -20,12 +20,12 @@ using File = Alphaleonis.Win32.Filesystem.File; using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; using Game = Wabbajack.Common.Game; using Path = Alphaleonis.Win32.Filesystem.Path; +#nullable enable namespace Wabbajack.Lib { public class MO2Compiler : ACompiler { - private AbsolutePath _mo2DownloadsFolder; public AbsolutePath MO2Folder; @@ -38,7 +38,7 @@ namespace Wabbajack.Lib public override AbsolutePath GamePath { get; } - public GameMetaData CompilingGame { get; set; } + public GameMetaData CompilingGame { get; } public override AbsolutePath ModListOutputFolder => ((RelativePath)"output_folder").RelativeToEntryPoint(); @@ -48,6 +48,17 @@ namespace Wabbajack.Lib Consts.LocalAppDataPath.Combine( $"vfs_compile_cache-{Path.Combine((string)MO2Folder ?? "Unknown", "ModOrganizer.exe").StringSha256Hex()}.bin"); + public dynamic MO2Ini { get; } + + public static AbsolutePath GetTypicalDownloadsFolder(AbsolutePath mo2Folder) => mo2Folder.Combine("downloads"); + + public AbsolutePath MO2ProfileDir => MO2Folder.Combine("profiles", MO2Profile); + + public ConcurrentBag ExtraFiles { get; } = new ConcurrentBag(); + public Dictionary ModInis { get; } = new Dictionary(); + + public HashSet SelectedProfiles { get; set; } = new HashSet(); + public MO2Compiler(AbsolutePath mo2Folder, string mo2Profile, AbsolutePath outputFile) : base(steps: 20) { @@ -60,8 +71,6 @@ namespace Wabbajack.Lib ModListOutputFile = outputFile; } - public dynamic MO2Ini { get; } - public AbsolutePath MO2DownloadsFolder { get @@ -76,16 +85,6 @@ namespace Wabbajack.Lib set => _mo2DownloadsFolder = value; } - public static AbsolutePath GetTypicalDownloadsFolder(AbsolutePath mo2Folder) => mo2Folder.Combine("downloads"); - - public AbsolutePath MO2ProfileDir => MO2Folder.Combine("profiles", MO2Profile); - - internal UserStatus User { get; private set; } - public ConcurrentBag ExtraFiles { get; private set; } - public Dictionary ModInis { get; private set; } - - public HashSet SelectedProfiles { get; set; } = new HashSet(); - protected override async Task _Begin(CancellationToken cancel) { if (cancel.IsCancellationRequested) return false; @@ -127,6 +126,11 @@ namespace Wabbajack.Lib if (lootPath.Exists) { + if (CompilingGame.MO2Name == null) + { + throw new ArgumentException("Compiling game had no MO2 name specified."); + } + var lootGameDirs = new [] { CompilingGame.MO2Name, // most of the games use the MO2 name @@ -217,10 +221,9 @@ namespace Wabbajack.Lib .GroupBy(f => f.Hash) .ToDictionary(f => f.Key, f => f.AsEnumerable()); - AllFiles = mo2Files.Concat(gameFiles) + AllFiles.SetTo(mo2Files.Concat(gameFiles) .Concat(lootFiles) - .DistinctBy(f => f.Path) - .ToList(); + .DistinctBy(f => f.Path)); Info($"Found {AllFiles.Count} files to build into mod list"); @@ -240,13 +243,10 @@ namespace Wabbajack.Lib Error($"Found {dups.Count} duplicates, exiting"); } - ExtraFiles = new ConcurrentBag(); - - if (cancel.IsCancellationRequested) return false; UpdateTracker.NextStep("Loading INIs"); - ModInis = MO2Folder.Combine(Consts.MO2ModFolderName) + ModInis.SetTo(MO2Folder.Combine(Consts.MO2ModFolderName) .EnumerateDirectories() .Select(f => { @@ -255,7 +255,7 @@ namespace Wabbajack.Lib return metaPath.Exists ? (mod_name: f, metaPath.LoadIniFile()) : default; }) .Where(f => f.Item1 != default) - .ToDictionary(f => f.Item1, f => f.Item2); + .Select(f => new KeyValuePair(f.Item1, f.Item2))); if (cancel.IsCancellationRequested) return false; var stack = MakeStack(); @@ -271,7 +271,7 @@ namespace Wabbajack.Lib PrintNoMatches(noMatch); if (CheckForNoMatchExit(noMatch)) return false; - InstallDirectives = results.Where(i => !(i is IgnoredDirectly)).ToList(); + InstallDirectives.SetTo(results.Where(i => !(i is IgnoredDirectly))); Info("Getting Nexus api_key, please click authorize if a browser window appears"); @@ -338,7 +338,7 @@ namespace Wabbajack.Lib { return a; } - })).Where(a => a != null).ToHashSet(); + })).NotNull().ToHashSet(); if (remove.Count == 0) return; @@ -390,7 +390,6 @@ namespace Wabbajack.Lib }); } - private async Task IncludeArchiveMetadata() { Utils.Log($"Including {SelectedArchives.Count} .meta files for downloads"); @@ -412,13 +411,12 @@ namespace Wabbajack.Lib /// private void ResetMembers() { - AllFiles = null; - InstallDirectives = null; - SelectedArchives = null; - ExtraFiles = null; + AllFiles.Clear(); + InstallDirectives.Clear(); + SelectedArchives.Clear(); + ExtraFiles.Clear(); } - /// /// Fills in the Patch fields in files that require them /// @@ -488,8 +486,7 @@ namespace Wabbajack.Lib return returnStream; } - Error($"Couldn't load data for {to}"); - return null; + throw new ArgumentException($"Couldn't load data for {to}"); } public override IEnumerable GetStack() @@ -568,12 +565,5 @@ namespace Wabbajack.Lib new DropAll(this) }; } - - public class IndexedFileMatch - { - public IndexedArchive Archive; - public IndexedArchiveEntry Entry; - public DateTime LastModified; - } } } From a30bba2c0bbc91dd572b58fac9a23dfdcab3428a Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 16:12:32 -0500 Subject: [PATCH 10/23] Inferencer nullability enabled --- .../UrlDownloaders/BethesdaNetInferencer.cs | 3 ++- .../Downloaders/UrlDownloaders/IUrlInferencer.cs | 3 ++- .../Downloaders/UrlDownloaders/YoutubeInferencer.cs | 10 +++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Wabbajack.Lib/Downloaders/UrlDownloaders/BethesdaNetInferencer.cs b/Wabbajack.Lib/Downloaders/UrlDownloaders/BethesdaNetInferencer.cs index 1265b46e..2dfd3cf2 100644 --- a/Wabbajack.Lib/Downloaders/UrlDownloaders/BethesdaNetInferencer.cs +++ b/Wabbajack.Lib/Downloaders/UrlDownloaders/BethesdaNetInferencer.cs @@ -1,11 +1,12 @@ using System; using System.Threading.Tasks; +#nullable enable namespace Wabbajack.Lib.Downloaders.UrlDownloaders { public class BethesdaNetInferencer : IUrlInferencer { - public async Task Infer(Uri uri) + public async Task Infer(Uri uri) { return BethesdaNetDownloader.StateFromUrl(uri); } diff --git a/Wabbajack.Lib/Downloaders/UrlDownloaders/IUrlInferencer.cs b/Wabbajack.Lib/Downloaders/UrlDownloaders/IUrlInferencer.cs index a0febfa3..84be4335 100644 --- a/Wabbajack.Lib/Downloaders/UrlDownloaders/IUrlInferencer.cs +++ b/Wabbajack.Lib/Downloaders/UrlDownloaders/IUrlInferencer.cs @@ -1,10 +1,11 @@ using System; using System.Threading.Tasks; +#nullable enable namespace Wabbajack.Lib.Downloaders.UrlDownloaders { public interface IUrlInferencer { - Task Infer(Uri uri); + Task Infer(Uri uri); } } diff --git a/Wabbajack.Lib/Downloaders/UrlDownloaders/YoutubeInferencer.cs b/Wabbajack.Lib/Downloaders/UrlDownloaders/YoutubeInferencer.cs index 66cff7eb..8c8d1974 100644 --- a/Wabbajack.Lib/Downloaders/UrlDownloaders/YoutubeInferencer.cs +++ b/Wabbajack.Lib/Downloaders/UrlDownloaders/YoutubeInferencer.cs @@ -3,15 +3,15 @@ using System.Linq; using System.Threading.Tasks; using Wabbajack.Common; using YoutubeExplode; +#nullable enable namespace Wabbajack.Lib.Downloaders.UrlDownloaders { public class YoutubeInferencer : IUrlInferencer { - - public async Task Infer(Uri uri) + public async Task Infer(Uri uri) { - var state = (YouTubeDownloader.State)YouTubeDownloader.UriToState(uri); + var state = YouTubeDownloader.UriToState(uri) as YouTubeDownloader.State; if (state == null) return null; var client = new YoutubeClient(Common.Http.ClientFactory.Client); @@ -24,13 +24,13 @@ namespace Wabbajack.Lib.Downloaders.UrlDownloaders .Select(line => { var segments = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); - if (segments.Length == 0) return (TimeSpan.Zero, null); + if (segments.Length == 0) return (TimeSpan.Zero, string.Empty); if (TryParseEx(segments.First(), out var s1)) return (s1, string.Join(" ", segments.Skip(1))); if (TryParseEx(Enumerable.Last(segments), out var s2)) return (s2, string.Join(" ", Utils.ButLast(segments))); - return (TimeSpan.Zero, null); + return (TimeSpan.Zero, string.Empty); }) .Where(t => t.Item2 != null) .ToList(); From 806ff74893d23b42ea5d8417f0268dd9c0d864dd Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 20:29:53 -0500 Subject: [PATCH 11/23] Wabbajack.Lib nullability finished up --- .../IndexedFilesTests.cs | 8 +- .../ModListValidationTests.cs | 19 ++-- Wabbajack.BuildServer.Test/ModlistUpdater.cs | 7 +- .../Controllers/IndexedFiles.cs | 3 +- .../Controllers/ModlistUpdater.cs | 20 ++-- .../Models/Jobs/EnqueueAllGameFiles.cs | 2 +- .../Models/Jobs/IndexDynDOLOD.cs | 3 +- .../Models/Jobs/UploadToCDN.cs | 3 +- .../Models/Sql/SqlService.cs | 6 +- Wabbajack.CLI/Verbs/Changelog.cs | 6 +- Wabbajack.CLI/Verbs/DeleteFile.cs | 2 +- Wabbajack.CLI/Verbs/DownloadUrl.cs | 2 +- Wabbajack.Common/Http/Client.cs | 2 +- .../StoreHandlers/SteamHandler.cs | 13 ++- Wabbajack.Lib/ABatchProcessor.cs | 1 - Wabbajack.Lib/ACompiler.cs | 6 +- Wabbajack.Lib/AInstaller.cs | 10 +- Wabbajack.Lib/ClientAPI.cs | 1 - .../CompilationSteps/ACompilationStep.cs | 1 - .../CompilationSteps/DeconstructBSAs.cs | 7 +- Wabbajack.Lib/CompilationSteps/DirectMatch.cs | 1 - Wabbajack.Lib/CompilationSteps/DropAll.cs | 1 - .../CompilationSteps/ICompilationStep.cs | 1 - .../CompilationSteps/IgnoreDisabledMods.cs | 1 - .../CompilationSteps/IgnoreEndsWith.cs | 1 - .../CompilationSteps/IgnoreGameFiles.cs | 1 - .../IgnoreGameFilesIfGameFolderFilesExist.cs | 1 - .../CompilationSteps/IgnorePathContains.cs | 1 - Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs | 1 - .../CompilationSteps/IgnoreStartsWith.cs | 1 - .../IgnoreWabbajackInstallCruft.cs | 1 - Wabbajack.Lib/CompilationSteps/IncludeAll.cs | 1 - .../CompilationSteps/IncludeAllConfigs.cs | 1 - .../CompilationSteps/IncludeDummyESPs.cs | 1 - .../CompilationSteps/IncludeLOOTFiles.cs | 1 - .../CompilationSteps/IncludeModIniData.cs | 1 - .../CompilationSteps/IncludeOtherProfiles.cs | 1 - .../CompilationSteps/IncludePatches.cs | 1 - .../CompilationSteps/IncludePropertyFiles.cs | 1 - .../CompilationSteps/IncludeRegex.cs | 1 - .../IncludeSteamWorkshopItems.cs | 1 - .../IncludeStubbedConfigfiles.cs | 1 - .../CompilationSteps/IncludeTaggedMods.cs | 1 - .../CompilationSteps/IncludeThisProfile.cs | 1 - .../IncludeVortexDeployment.cs | 1 - .../CompilationSteps/PatchStockESMs.cs | 1 - Wabbajack.Lib/Data.cs | 85 ++++++++--------- .../Downloaders/AFKModsDownloader.cs | 1 - .../Downloaders/AbstractDownloadState.cs | 5 +- .../Downloaders/AbstractIPS4Downloader.cs | 1 - .../AbstractNeedsLoginDownloader.cs | 22 +++-- .../Downloaders/BethesdaNetDownloader.cs | 1 - .../Downloaders/DeadlyStreamDownloader.cs | 1 - .../Downloaders/DownloadDispatcher.cs | 7 +- Wabbajack.Lib/Downloaders/DownloaderUtils.cs | 2 +- .../Downloaders/DropboxDownloader.cs | 1 - .../Downloaders/GameFileSourceDownloader.cs | 1 - .../Downloaders/GoogleDriveDownloader.cs | 1 - Wabbajack.Lib/Downloaders/HTTPDownloader.cs | 1 - Wabbajack.Lib/Downloaders/IDownloader.cs | 1 - Wabbajack.Lib/Downloaders/INeedsLogin.cs | 3 +- Wabbajack.Lib/Downloaders/IUrlDownloader.cs | 2 +- .../Downloaders/LoversLabDownloader.cs | 1 - Wabbajack.Lib/Downloaders/MEGADownloader.cs | 1 - Wabbajack.Lib/Downloaders/ManualDownloader.cs | 1 - .../Downloaders/MediaFireDownloader.cs | 1 - Wabbajack.Lib/Downloaders/ModDBDownloader.cs | 1 - Wabbajack.Lib/Downloaders/NexusDownloader.cs | 1 - .../Downloaders/SteamWorkshopDownloader.cs | 23 +++-- .../Downloaders/TESAllianceDownloader.cs | 1 - .../UrlDownloaders/BethesdaNetInferencer.cs | 1 - .../UrlDownloaders/IUrlInferencer.cs | 1 - .../UrlDownloaders/YoutubeInferencer.cs | 1 - .../Downloaders/VectorPlexusDownloader.cs | 1 - .../Downloaders/YouTubeDownloader.cs | 1 - Wabbajack.Lib/Exceptions/HttpException.cs | 1 - Wabbajack.Lib/FileUploader/AuthorAPI.cs | 8 +- Wabbajack.Lib/IBatchProcessor.cs | 1 - Wabbajack.Lib/LibCefHelpers/Init.cs | 8 +- Wabbajack.Lib/MO2Compiler.cs | 4 +- Wabbajack.Lib/MO2Installer.cs | 5 +- Wabbajack.Lib/Manifest.cs | 4 +- .../ModListRegistry/ModListMetadata.cs | 31 +++--- Wabbajack.Lib/NexusApi/Dtos.cs | 50 +++++----- Wabbajack.Lib/NexusApi/NexusApi.cs | 22 ++--- Wabbajack.Lib/NexusApi/NexusApiUtils.cs | 13 +-- .../NexusApi/RequestNexusAuthorization.cs | 2 +- .../ConfirmUpdateOfExistingInstall.cs | 2 +- .../StatusMessages/ManuallyDownloadFile.cs | 6 +- .../ManuallyDownloadNexusFile.cs | 6 +- Wabbajack.Lib/SystemParameters.cs | 1 - Wabbajack.Lib/Validation/DTOs.cs | 43 +++++---- Wabbajack.Lib/ViewModel.cs | 1 - Wabbajack.Lib/VortexCompiler.cs | 1 - Wabbajack.Lib/Wabbajack.Lib.csproj | 7 +- .../WebAutomation/CefSharpWrapper.cs | 14 ++- Wabbajack.Lib/WebAutomation/IWebDriver.cs | 2 +- Wabbajack.Lib/WebAutomation/WebAutomation.cs | 4 +- Wabbajack.Lib/zEditIntegration.cs | 12 +-- .../ContentRightsManagementTests.cs | 20 ++-- Wabbajack.Test/DownloaderTests.cs | 94 +++++++++---------- Wabbajack.Test/EndToEndTests.cs | 2 +- Wabbajack.Test/ModlistMetadataTests.cs | 2 +- .../View Models/Gallery/ModListMetadataVM.cs | 2 +- 104 files changed, 299 insertions(+), 387 deletions(-) diff --git a/Wabbajack.BuildServer.Test/IndexedFilesTests.cs b/Wabbajack.BuildServer.Test/IndexedFilesTests.cs index e8d594bc..c7af0997 100644 --- a/Wabbajack.BuildServer.Test/IndexedFilesTests.cs +++ b/Wabbajack.BuildServer.Test/IndexedFilesTests.cs @@ -53,14 +53,14 @@ namespace Wabbajack.BuildServer.Test public async Task CanNotifyOfInis() { var archive = - new Archive - { - State = new NexusDownloader.State + new Archive( + new NexusDownloader.State { Game = Game.SkyrimSpecialEdition, ModID = long.MaxValue >> 3, FileID = long.MaxValue >> 3, - }, + }) + { Name = Guid.NewGuid().ToString() }; Assert.True(await AuthorAPI.UploadPackagedInis(new[] {archive})); diff --git a/Wabbajack.BuildServer.Test/ModListValidationTests.cs b/Wabbajack.BuildServer.Test/ModListValidationTests.cs index 434cc824..761d2b5c 100644 --- a/Wabbajack.BuildServer.Test/ModListValidationTests.cs +++ b/Wabbajack.BuildServer.Test/ModListValidationTests.cs @@ -121,19 +121,14 @@ namespace Wabbajack.BuildServer.Test - var modListData = new ModList - { - Archives = new List + var modListData = new ModList(); + modListData.Archives.Add( + new Archive(new HTTPDownloader.State(MakeURL("test_archive.txt"))) { - new Archive - { - Hash = await test_archive_path.FileHashAsync(), - Name = "test_archive", - Size = test_archive_path.Size, - State = new HTTPDownloader.State(MakeURL("test_archive.txt")) - } - } - }; + Hash = await test_archive_path.FileHashAsync(), + Name = "test_archive", + Size = test_archive_path.Size, + }); var modListPath = "test_modlist.wabbajack".RelativeTo(Fixture.ServerPublicFolder); diff --git a/Wabbajack.BuildServer.Test/ModlistUpdater.cs b/Wabbajack.BuildServer.Test/ModlistUpdater.cs index e7d62c15..3a9a5f5d 100644 --- a/Wabbajack.BuildServer.Test/ModlistUpdater.cs +++ b/Wabbajack.BuildServer.Test/ModlistUpdater.cs @@ -42,10 +42,9 @@ namespace Wabbajack.BuildServer.Test { Payload = new IndexJob { - Archive = new Archive + Archive = new Archive(new HTTPDownloader.State(MakeURL("old_file_data.random"))) { Name = "Oldfile", - State = new HTTPDownloader.State(MakeURL("old_file_data.random")) } } }); @@ -54,10 +53,9 @@ namespace Wabbajack.BuildServer.Test { Payload = new IndexJob { - Archive = new Archive + Archive = new Archive(new HTTPDownloader.State(MakeURL("new_file_data.random"))) { Name = "Newfile", - State = new HTTPDownloader.State(MakeURL("new_file_data.random")) } } }); @@ -120,6 +118,5 @@ namespace Wabbajack.BuildServer.Test Assert.True($"{oldDataHash.ToHex()}_{newDataHash.ToHex()}".RelativeTo(Fixture.ServerUpdatesFolder).IsFile); } - } } diff --git a/Wabbajack.BuildServer/Controllers/IndexedFiles.cs b/Wabbajack.BuildServer/Controllers/IndexedFiles.cs index 6db8b742..30587e1a 100644 --- a/Wabbajack.BuildServer/Controllers/IndexedFiles.cs +++ b/Wabbajack.BuildServer/Controllers/IndexedFiles.cs @@ -102,10 +102,9 @@ namespace Wabbajack.BuildServer.Controllers Priority = Job.JobPriority.Low, Payload = new IndexJob { - Archive = new Archive + Archive = new Archive(data) { Name = entry.Name, - State = data } } }); diff --git a/Wabbajack.BuildServer/Controllers/ModlistUpdater.cs b/Wabbajack.BuildServer/Controllers/ModlistUpdater.cs index 1ccb2e11..3b6fca2c 100644 --- a/Wabbajack.BuildServer/Controllers/ModlistUpdater.cs +++ b/Wabbajack.BuildServer/Controllers/ModlistUpdater.cs @@ -175,15 +175,19 @@ namespace Wabbajack.BuildServer.Controllers var allMods = await api.GetModFiles(state.Game, state.ModID); var archive = allMods.files.Where(m => !string.IsNullOrEmpty(m.category_name)) .OrderBy(s => Math.Abs((long)s.size - origSize)) - .Select(s => new Archive { - Name = s.file_name, - Size = (long)s.size, - State = new NexusDownloader.State + .Select(s => + new Archive( + new NexusDownloader.State + { + Game = state.Game, + ModID = state.ModID, + FileID = s.file_id + }) { - Game = state.Game, - ModID = state.ModID, - FileID = s.file_id - }}).FirstOrDefault(); + Name = s.file_name, + Size = (long)s.size, + }) + .FirstOrDefault(); if (archive == null) { diff --git a/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs b/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs index 7f42cf04..f628f69c 100644 --- a/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs +++ b/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs @@ -53,7 +53,7 @@ namespace Wabbajack.BuildServer.Models.Jobs var with_hash = states.Where(state => state.Hash != default).ToList(); Utils.Log($"Inserting {with_hash.Count} jobs."); - var jobs = states.Select(state => new IndexJob {Archive = new Archive {Name = state.GameFile.FileName.ToString(), State = state}}) + var jobs = states.Select(state => new IndexJob {Archive = new Archive(state) { Name = state.GameFile.FileName.ToString()}}) .Select(j => new Job {Payload = j, RequiresNexus = j.UsesNexus}) .ToList(); diff --git a/Wabbajack.BuildServer/Models/Jobs/IndexDynDOLOD.cs b/Wabbajack.BuildServer/Models/Jobs/IndexDynDOLOD.cs index 20353260..7f065767 100644 --- a/Wabbajack.BuildServer/Models/Jobs/IndexDynDOLOD.cs +++ b/Wabbajack.BuildServer/Models/Jobs/IndexDynDOLOD.cs @@ -38,10 +38,9 @@ namespace Wabbajack.BuildServer.Models.Jobs { Payload = new IndexJob { - Archive = new Archive + Archive = new Archive(new MegaDownloader.State(url.ToString())) { Name = Guid.NewGuid() + ".7z", - State = new MegaDownloader.State(url.ToString()) } } }) diff --git a/Wabbajack.BuildServer/Models/Jobs/UploadToCDN.cs b/Wabbajack.BuildServer/Models/Jobs/UploadToCDN.cs index 1b9fa398..e3639aca 100644 --- a/Wabbajack.BuildServer/Models/Jobs/UploadToCDN.cs +++ b/Wabbajack.BuildServer/Models/Jobs/UploadToCDN.cs @@ -56,12 +56,11 @@ namespace Wabbajack.BuildServer.Models.Jobs Priority = Job.JobPriority.High, Payload = new IndexJob { - Archive = new Archive + Archive = new Archive(new HTTPDownloader.State(file.Uri)) { Name = file.MungedName, Size = file.Size, Hash = file.Hash, - State = new HTTPDownloader.State(file.Uri) } } }); diff --git a/Wabbajack.BuildServer/Models/Sql/SqlService.cs b/Wabbajack.BuildServer/Models/Sql/SqlService.cs index b1756323..24223f80 100644 --- a/Wabbajack.BuildServer/Models/Sql/SqlService.cs +++ b/Wabbajack.BuildServer/Models/Sql/SqlService.cs @@ -519,9 +519,8 @@ namespace Wabbajack.BuildServer.Model.Models var result = await conn.QueryFirstOrDefaultAsync(@"SELECT JsonState FROM dbo.DownloadStates WHERE Hash = @hash AND PrimaryKey like 'NexusDownloader+State|%'", new {Hash = (long)startingHash}); - return result == null ? null : new Archive + return result == null ? null : new Archive(result.FromJsonString()) { - State = result.FromJsonString(), Hash = startingHash }; } @@ -531,9 +530,8 @@ namespace Wabbajack.BuildServer.Model.Models await using var conn = await Open(); var result = await conn.QueryFirstOrDefaultAsync<(long Hash, string State)>(@"SELECT Hash, JsonState FROM dbo.DownloadStates WHERE PrimaryKey = @PrimaryKey", new {PrimaryKey = primaryKey}); - return result == default ? null : new Archive + return result == default ? null : new Archive(result.State.FromJsonString()) { - State = result.State.FromJsonString(), Hash = Hash.FromLong(result.Hash) }; } diff --git a/Wabbajack.CLI/Verbs/Changelog.cs b/Wabbajack.CLI/Verbs/Changelog.cs index 8ed0462d..63549a01 100644 --- a/Wabbajack.CLI/Verbs/Changelog.cs +++ b/Wabbajack.CLI/Verbs/Changelog.cs @@ -318,7 +318,7 @@ namespace Wabbajack.CLI.Verbs private static async Task GetTextFileFromModlist(AbsolutePath archive, ModList modlist, RelativePath sourceID) { - var installer = new MO2Installer(archive, modlist, default, default, null); + var installer = new MO2Installer(archive, modlist, default, default, parameters: null!); byte[] bytes = await installer.LoadBytesFromPath(sourceID); return Encoding.Default.GetString(bytes); } @@ -328,9 +328,9 @@ namespace Wabbajack.CLI.Verbs return header.Trim().Replace(" ", "").Replace(".", ""); } - private static string GetModName(Archive a) + private static string? GetModName(Archive a) { - var result = a.Name; + string? result = a.Name; if (a.State is IMetaState metaState) { diff --git a/Wabbajack.CLI/Verbs/DeleteFile.cs b/Wabbajack.CLI/Verbs/DeleteFile.cs index 2b48617e..a0de0efa 100644 --- a/Wabbajack.CLI/Verbs/DeleteFile.cs +++ b/Wabbajack.CLI/Verbs/DeleteFile.cs @@ -9,7 +9,7 @@ namespace Wabbajack.CLI.Verbs public class DeleteFile : AVerb { [Option('n', "name", Required = true, HelpText = @"Full name (as returned by my-files) of the file")] - public string? Name { get; set; } + public string Name { get; set; } = null!; protected override async Task Run() { diff --git a/Wabbajack.CLI/Verbs/DownloadUrl.cs b/Wabbajack.CLI/Verbs/DownloadUrl.cs index 9ea450a2..6263c649 100644 --- a/Wabbajack.CLI/Verbs/DownloadUrl.cs +++ b/Wabbajack.CLI/Verbs/DownloadUrl.cs @@ -35,7 +35,7 @@ namespace Wabbajack.CLI.Verbs new[] {state} .PMap(queue, async s => { - await s.Download(new Archive {Name = Path.GetFileName(Output)}, (AbsolutePath)Output); + await s.Download(new Archive(state: null!) {Name = Path.GetFileName(Output)}, (AbsolutePath)Output); }).Wait(); File.WriteAllLines(Output + ".meta", state.GetMetaIni()); diff --git a/Wabbajack.Common/Http/Client.cs b/Wabbajack.Common/Http/Client.cs index 098f8866..3a7bfb0a 100644 --- a/Wabbajack.Common/Http/Client.cs +++ b/Wabbajack.Common/Http/Client.cs @@ -11,7 +11,7 @@ namespace Wabbajack.Common.Http { public class Client { - public List<(string, string)> Headers = new List<(string, string)>(); + public List<(string, string?)> Headers = new List<(string, string?)>(); public List Cookies = new List(); public async Task GetAsync(string url, HttpCompletionOption responseHeadersRead = HttpCompletionOption.ResponseHeadersRead) { diff --git a/Wabbajack.Common/StoreHandlers/SteamHandler.cs b/Wabbajack.Common/StoreHandlers/SteamHandler.cs index c84e7794..6f9af723 100644 --- a/Wabbajack.Common/StoreHandlers/SteamHandler.cs +++ b/Wabbajack.Common/StoreHandlers/SteamHandler.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Security; using DynamicData; using Microsoft.Win32; +#nullable enable namespace Wabbajack.Common.StoreHandlers { @@ -21,9 +22,14 @@ namespace Wabbajack.Common.StoreHandlers public class SteamWorkshopItem { - public SteamGame? Game; + public readonly SteamGame Game; public int ItemID; public int Size; + + public SteamWorkshopItem(SteamGame game) + { + Game = game; + } } public class SteamHandler : AStoreHandler @@ -202,14 +208,14 @@ namespace Wabbajack.Common.StoreHandlers var bracketStart = 0; var bracketEnd = 0; - SteamWorkshopItem? currentItem = new SteamWorkshopItem(); + SteamWorkshopItem? currentItem = new SteamWorkshopItem(game); lines.Do(l => { if (end) return; if (currentItem == null) - currentItem = new SteamWorkshopItem(); + currentItem = new SteamWorkshopItem(game); var currentLine = lines.IndexOf(l); if (l.ContainsCaseInsensitive("\"appid\"") && !foundAppID) @@ -271,7 +277,6 @@ namespace Wabbajack.Common.StoreHandlers bracketStart = 0; bracketEnd = 0; - currentItem.Game = game; game.WorkshopItems.Add(currentItem); Utils.Log($"Found Steam Workshop item {currentItem.ItemID}"); diff --git a/Wabbajack.Lib/ABatchProcessor.cs b/Wabbajack.Lib/ABatchProcessor.cs index ef775efc..12a0aab8 100644 --- a/Wabbajack.Lib/ABatchProcessor.cs +++ b/Wabbajack.Lib/ABatchProcessor.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Wabbajack.Common; using Wabbajack.Common.StatusFeed; using Wabbajack.VirtualFileSystem; -#nullable enable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/ACompiler.cs b/Wabbajack.Lib/ACompiler.cs index ef5490eb..06654835 100644 --- a/Wabbajack.Lib/ACompiler.cs +++ b/Wabbajack.Lib/ACompiler.cs @@ -14,7 +14,6 @@ using Wabbajack.VirtualFileSystem; using Directory = Alphaleonis.Win32.Filesystem.Directory; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; -#nullable enable namespace Wabbajack.Lib { @@ -243,10 +242,7 @@ namespace Wabbajack.Lib Error( $"No download metadata found for {archive.Name}, please use MO2 to query info or add a .meta file and try again."); - var result = new Archive - { - State = await DownloadDispatcher.ResolveArchive(archive.IniData) - }; + var result = new Archive(await DownloadDispatcher.ResolveArchive(archive.IniData)); if (result.State == null) Error($"{archive.Name} could not be handled by any of the downloaders"); diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index ac103756..2ddbceda 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -13,7 +13,6 @@ using Directory = Alphaleonis.Win32.Filesystem.Directory; using File = Alphaleonis.Win32.Filesystem.File; using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; using Path = Alphaleonis.Win32.Filesystem.Path; -#nullable enable namespace Wabbajack.Lib { @@ -30,9 +29,9 @@ namespace Wabbajack.Lib public ModList ModList { get; private set; } public Dictionary HashedArchives { get; } = new Dictionary(); - public SystemParameters SystemParameters { get; set; } + public SystemParameters? SystemParameters { get; set; } - public AInstaller(AbsolutePath archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters, int steps) + public AInstaller(AbsolutePath archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters? parameters, int steps) : base(steps) { ModList = modList; @@ -168,6 +167,10 @@ namespace Wabbajack.Lib .PDoIndexed(queue, async (idx, group) => { Utils.Status("Installing files", Percent.FactoryPutInRange(idx, vFiles.Count)); + if (group.Key == null) + { + throw new ArgumentNullException("FromFile was null"); + } var firstDest = OutputFolder.Combine(group.First().To); await CopyFile(group.Key.StagedPath, firstDest, true); @@ -175,7 +178,6 @@ namespace Wabbajack.Lib { await CopyFile(firstDest, OutputFolder.Combine(copy.To), false); } - }); Status("Unstaging files"); diff --git a/Wabbajack.Lib/ClientAPI.cs b/Wabbajack.Lib/ClientAPI.cs index 80fc2043..959fbbf7 100644 --- a/Wabbajack.Lib/ClientAPI.cs +++ b/Wabbajack.Lib/ClientAPI.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Wabbajack.Common; using Wabbajack.Lib.Exceptions; -#nullable enable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/CompilationSteps/ACompilationStep.cs b/Wabbajack.Lib/CompilationSteps/ACompilationStep.cs index 4427334f..e00ac6e7 100644 --- a/Wabbajack.Lib/CompilationSteps/ACompilationStep.cs +++ b/Wabbajack.Lib/CompilationSteps/ACompilationStep.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs b/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs index d8ea17f5..5e37d3d4 100644 --- a/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs +++ b/Wabbajack.Lib/CompilationSteps/DeconstructBSAs.cs @@ -8,7 +8,6 @@ using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Common.StatusFeed.Errors; using Wabbajack.VirtualFileSystem; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { @@ -80,12 +79,12 @@ namespace Wabbajack.Lib.CompilationSteps CreateBSA directive; using (var bsa = BSADispatch.OpenRead(source.AbsolutePath)) { - directive = new CreateBSA + directive = new CreateBSA( + state: bsa.State, + items: bsa.Files.Select(f => f.State).ToList()) { To = source.Path, TempID = (RelativePath)id, - State = bsa.State, - FileStates = bsa.Files.Select(f => f.State).ToList() }; } diff --git a/Wabbajack.Lib/CompilationSteps/DirectMatch.cs b/Wabbajack.Lib/CompilationSteps/DirectMatch.cs index 6f883117..0f57cee3 100644 --- a/Wabbajack.Lib/CompilationSteps/DirectMatch.cs +++ b/Wabbajack.Lib/CompilationSteps/DirectMatch.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/DropAll.cs b/Wabbajack.Lib/CompilationSteps/DropAll.cs index 0c3a6fc4..bcbc32f3 100644 --- a/Wabbajack.Lib/CompilationSteps/DropAll.cs +++ b/Wabbajack.Lib/CompilationSteps/DropAll.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/ICompilationStep.cs b/Wabbajack.Lib/CompilationSteps/ICompilationStep.cs index 68b8b73b..eafa5914 100644 --- a/Wabbajack.Lib/CompilationSteps/ICompilationStep.cs +++ b/Wabbajack.Lib/CompilationSteps/ICompilationStep.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs b/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs index f9b9f1bc..3fd9912b 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreDisabledMods.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreEndsWith.cs b/Wabbajack.Lib/CompilationSteps/IgnoreEndsWith.cs index 53b44621..b9918d95 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreEndsWith.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreEndsWith.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Newtonsoft.Json; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreGameFiles.cs b/Wabbajack.Lib/CompilationSteps/IgnoreGameFiles.cs index 9b95d35d..7581c566 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreGameFiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreGameFiles.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs b/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs index 59026899..6f86f783 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreGameFilesIfGameFolderFilesExist.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IgnorePathContains.cs b/Wabbajack.Lib/CompilationSteps/IgnorePathContains.cs index 1a8c627b..eac01fe7 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnorePathContains.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnorePathContains.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Newtonsoft.Json; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs b/Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs index abf48183..739ad00c 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreRegex.cs @@ -1,7 +1,6 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Newtonsoft.Json; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreStartsWith.cs b/Wabbajack.Lib/CompilationSteps/IgnoreStartsWith.cs index 087ea169..5abad699 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreStartsWith.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreStartsWith.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Newtonsoft.Json; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IgnoreWabbajackInstallCruft.cs b/Wabbajack.Lib/CompilationSteps/IgnoreWabbajackInstallCruft.cs index c1f36243..e8e71212 100644 --- a/Wabbajack.Lib/CompilationSteps/IgnoreWabbajackInstallCruft.cs +++ b/Wabbajack.Lib/CompilationSteps/IgnoreWabbajackInstallCruft.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Threading.Tasks; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeAll.cs b/Wabbajack.Lib/CompilationSteps/IncludeAll.cs index 6f229c45..db63b34b 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeAll.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeAll.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeAllConfigs.cs b/Wabbajack.Lib/CompilationSteps/IncludeAllConfigs.cs index eb73f724..9bf53920 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeAllConfigs.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeAllConfigs.cs @@ -2,7 +2,6 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeDummyESPs.cs b/Wabbajack.Lib/CompilationSteps/IncludeDummyESPs.cs index 127d7555..89466c52 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeDummyESPs.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeDummyESPs.cs @@ -2,7 +2,6 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeLOOTFiles.cs b/Wabbajack.Lib/CompilationSteps/IncludeLOOTFiles.cs index a34e0a3f..5a89a131 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeLOOTFiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeLOOTFiles.cs @@ -2,7 +2,6 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeModIniData.cs b/Wabbajack.Lib/CompilationSteps/IncludeModIniData.cs index 70bc66b8..f1def248 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeModIniData.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeModIniData.cs @@ -2,7 +2,6 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeOtherProfiles.cs b/Wabbajack.Lib/CompilationSteps/IncludeOtherProfiles.cs index a6190347..9c89d361 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeOtherProfiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeOtherProfiles.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludePatches.cs b/Wabbajack.Lib/CompilationSteps/IncludePatches.cs index 228cc7e3..65cb6b40 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludePatches.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludePatches.cs @@ -6,7 +6,6 @@ using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.VirtualFileSystem; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludePropertyFiles.cs b/Wabbajack.Lib/CompilationSteps/IncludePropertyFiles.cs index eb877762..3add0f20 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludePropertyFiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludePropertyFiles.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeRegex.cs b/Wabbajack.Lib/CompilationSteps/IncludeRegex.cs index e5fbda99..edd9128c 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeRegex.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeRegex.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs b/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs index 68cd72bd..1bcbef60 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Wabbajack.Common; using Wabbajack.Common.StoreHandlers; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeStubbedConfigfiles.cs b/Wabbajack.Lib/CompilationSteps/IncludeStubbedConfigfiles.cs index b1c1abff..392cb1b3 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeStubbedConfigfiles.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeStubbedConfigfiles.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeTaggedMods.cs b/Wabbajack.Lib/CompilationSteps/IncludeTaggedMods.cs index 2409568a..d2d8a06f 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeTaggedMods.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeTaggedMods.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeThisProfile.cs b/Wabbajack.Lib/CompilationSteps/IncludeThisProfile.cs index d01cf628..4d0141a3 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeThisProfile.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeThisProfile.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Newtonsoft.Json; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs b/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs index 303afbfa..19a386dc 100644 --- a/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs +++ b/Wabbajack.Lib/CompilationSteps/IncludeVortexDeployment.cs @@ -3,7 +3,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/CompilationSteps/PatchStockESMs.cs b/Wabbajack.Lib/CompilationSteps/PatchStockESMs.cs index fabc3072..2a8f9d12 100644 --- a/Wabbajack.Lib/CompilationSteps/PatchStockESMs.cs +++ b/Wabbajack.Lib/CompilationSteps/PatchStockESMs.cs @@ -4,7 +4,6 @@ using Newtonsoft.Json; using Wabbajack.Common; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; -#nullable enable namespace Wabbajack.Lib.CompilationSteps { diff --git a/Wabbajack.Lib/Data.cs b/Wabbajack.Lib/Data.cs index c48e75ac..4fe5a4c5 100644 --- a/Wabbajack.Lib/Data.cs +++ b/Wabbajack.Lib/Data.cs @@ -43,22 +43,22 @@ namespace Wabbajack.Lib /// /// Archives required by this modlist /// - public List Archives; + public List Archives = new List(); /// /// Author of the ModList /// - public string Author; + public string Author = string.Empty; /// /// Description of the ModList /// - public string Description; + public string Description = string.Empty; /// /// Install directives /// - public List Directives; + public List Directives = new List(); /// /// The game variant to which this game applies @@ -78,12 +78,12 @@ namespace Wabbajack.Lib /// /// Name of the ModList /// - public string Name; + public string Name = string.Empty; /// /// readme path or website /// - public string Readme; + public string Readme = string.Empty; /// /// Whether readme is a website @@ -93,12 +93,12 @@ namespace Wabbajack.Lib /// /// The build version of Wabbajack used when compiling the Modlist /// - public Version WabbajackVersion; + public Version? WabbajackVersion; /// /// Website of the ModList /// - public Uri Website; + public Uri? Website; /// /// The size of all the archives once they're downloaded @@ -134,7 +134,7 @@ namespace Wabbajack.Lib public class IgnoredDirectly : Directive { - public string Reason; + public string Reason = string.Empty; } public class NoMatch : IgnoredDirectly @@ -190,12 +190,12 @@ namespace Wabbajack.Lib [JsonName("FromArchive")] public class FromArchive : Directive { - private string _fullPath; + private string? _fullPath; public HashRelativePath ArchiveHashPath { get; set; } [JsonIgnore] - public VirtualFile FromFile { get; set; } + public VirtualFile? FromFile { get; set; } [JsonIgnore] public string FullPath => _fullPath ??= string.Join("|", ArchiveHashPath); @@ -205,8 +205,17 @@ namespace Wabbajack.Lib public class CreateBSA : Directive { public RelativePath TempID { get; set; } - public ArchiveStateObject State { get; set; } - public List FileStates { get; set; } + public ArchiveStateObject State { get; } + public List FileStates { get; set; } = new List(); + + public CreateBSA(ArchiveStateObject state, IEnumerable? items = null) + { + State = state; + if (items != null) + { + FileStates.AddRange(items); + } + } } [JsonName("PatchedFromArchive")] @@ -231,7 +240,7 @@ namespace Wabbajack.Lib public class MergedPatch : Directive { public RelativePath PatchID { get; set; } - public List Sources { get; set; } + public List Sources { get; set; } = new List(); } [JsonName("Archive")] @@ -245,49 +254,33 @@ namespace Wabbajack.Lib /// /// Meta INI for the downloaded archive /// - public string Meta { get; set; } + public string? Meta { get; set; } /// /// Human friendly name of this archive /// - public string Name { get; set; } + public string Name { get; set; } = string.Empty; public long Size { get; set; } - public AbstractDownloadState State { get; set; } + public AbstractDownloadState State { get; } + + public Archive(AbstractDownloadState state) + { + State = state; + } } public class IndexedArchive { - public dynamic IniData; - public string Meta; - public string Name; - public VirtualFile File { get; internal set; } - } + public dynamic? IniData; + public string Meta = string.Empty; + public string Name = string.Empty; + public VirtualFile File { get; } - /// - /// A archive entry - /// - public class IndexedEntry - { - /// - /// MurMur3 hash of this file - /// - public string Hash; - - /// - /// Path in the archive to this file - /// - public string Path; - - /// - /// Size of the file (uncompressed) - /// - public long Size; - } - - public class IndexedArchiveEntry : IndexedEntry - { - public string[] HashPath; + public IndexedArchive(VirtualFile file) + { + File = file; + } } } diff --git a/Wabbajack.Lib/Downloaders/AFKModsDownloader.cs b/Wabbajack.Lib/Downloaders/AFKModsDownloader.cs index 62f84da3..fdeb1385 100644 --- a/Wabbajack.Lib/Downloaders/AFKModsDownloader.cs +++ b/Wabbajack.Lib/Downloaders/AFKModsDownloader.cs @@ -1,5 +1,4 @@ using System; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs index 196934d7..e5ea3c75 100644 --- a/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs +++ b/Wabbajack.Lib/Downloaders/AbstractDownloadState.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Lib.Validation; -#nullable enable namespace Wabbajack.Lib.Downloaders { @@ -84,7 +83,9 @@ namespace Wabbajack.Lib.Downloaders public async Task Download(AbsolutePath destination) { destination.Parent.CreateDirectory(); - return await Download(new Archive {Name = (string)destination.FileName}, destination); + // ToDo + // Is this null override needed? Why is state allowed to be null here? + return await Download(new Archive(state: null!) {Name = (string)destination.FileName}, destination); } /// diff --git a/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs b/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs index 5bff0424..cca6e4cc 100644 --- a/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs +++ b/Wabbajack.Lib/Downloaders/AbstractIPS4Downloader.cs @@ -8,7 +8,6 @@ using System.Web; using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Lib.Validation; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs index e256b1b4..a6a4e681 100644 --- a/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs +++ b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs @@ -21,7 +21,17 @@ namespace Wabbajack.Lib.Downloaders private readonly string _encryptedKeyName; private readonly string _cookieDomain; private readonly string _cookieName; - internal Common.Http.Client AuthedClient; + // ToDo + // Remove null assignment. Either add nullability to type, or figure way to prepare it safely + public Common.Http.Client AuthedClient { get; private set; } = null!; + + public ReactiveCommand TriggerLogin { get; } + public ReactiveCommand ClearLogin { get; } + public IObservable IsLoggedIn => Utils.HaveEncryptedJsonObservable(_encryptedKeyName); + public abstract string SiteName { get; } + public virtual IObservable? MetaInfo { get; } + public abstract Uri SiteURL { get; } + public virtual Uri? IconUri { get; } /// /// Sets up all the login facilites needed for a INeedsLogin downloader based on having the user log @@ -48,14 +58,6 @@ namespace Wabbajack.Lib.Downloaders execute: () => Utils.CatchAndLog(() => Utils.DeleteEncryptedJson(_encryptedKeyName)), canExecute: IsLoggedIn.ObserveOnGuiThread()); } - - public ReactiveCommand TriggerLogin { get; } - public ReactiveCommand ClearLogin { get; } - public IObservable IsLoggedIn => Utils.HaveEncryptedJsonObservable(_encryptedKeyName); - public abstract string SiteName { get; } - public virtual IObservable MetaInfo { get; } - public abstract Uri SiteURL { get; } - public virtual Uri IconUri { get; } protected virtual async Task WhileWaiting(IWebDriver browser) { @@ -120,7 +122,7 @@ namespace Wabbajack.Lib.Downloaders Downloader = downloader; } public override string ShortDescription => $"Getting {Downloader.SiteName} Login"; - public override string ExtendedDescription { get; } + public override string ExtendedDescription { get; } = string.Empty; private readonly TaskCompletionSource _source = new TaskCompletionSource(); public Task Task => _source.Task; diff --git a/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs b/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs index 8ca7a9f3..f7b9ea30 100644 --- a/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs +++ b/Wabbajack.Lib/Downloaders/BethesdaNetDownloader.cs @@ -24,7 +24,6 @@ using Wabbajack.Lib.Validation; using File = Alphaleonis.Win32.Filesystem.File; using Game = Wabbajack.Common.Game; using Path = Alphaleonis.Win32.Filesystem.Path; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs b/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs index a1131998..2da650c1 100644 --- a/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs +++ b/Wabbajack.Lib/Downloaders/DeadlyStreamDownloader.cs @@ -1,5 +1,4 @@ using System; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs b/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs index 7bdb271a..4c680dfe 100644 --- a/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs +++ b/Wabbajack.Lib/Downloaders/DownloadDispatcher.cs @@ -43,7 +43,7 @@ namespace Wabbajack.Lib.Downloaders IndexedDownloaders = Downloaders.ToDictionary(d => d.GetType()); } - public static async Task Infer(Uri uri) + public static async Task Infer(Uri uri) { foreach (var inf in Inferencers) { @@ -74,7 +74,7 @@ namespace Wabbajack.Lib.Downloaders /// /// /// - public static AbstractDownloadState ResolveArchive(string url) + public static AbstractDownloadState? ResolveArchive(string url) { return Downloaders.OfType().Select(d => d.GetDownloaderState(url)).FirstOrDefault(result => result != null); } @@ -112,10 +112,9 @@ namespace Wabbajack.Lib.Downloaders var patchName = $"{archive.Hash.ToHex()}_{upgrade.Hash.ToHex()}"; var patchPath = destination.Parent.Combine("_Patch_" + patchName); - var patchState = new Archive + var patchState = new Archive(new HTTPDownloader.State($"https://wabbajackcdn.b-cdn.net/updates/{patchName}")) { Name = patchName, - State = new HTTPDownloader.State($"https://wabbajackcdn.b-cdn.net/updates/{patchName}") }; var patchResult = await Download(patchState, patchPath); diff --git a/Wabbajack.Lib/Downloaders/DownloaderUtils.cs b/Wabbajack.Lib/Downloaders/DownloaderUtils.cs index fbe309d8..f798856f 100644 --- a/Wabbajack.Lib/Downloaders/DownloaderUtils.cs +++ b/Wabbajack.Lib/Downloaders/DownloaderUtils.cs @@ -4,7 +4,7 @@ namespace Wabbajack.Lib.Downloaders { public static class DownloaderUtils { - public static Uri GetDirectURL(dynamic meta) + public static Uri? GetDirectURL(dynamic? meta) { var url = meta?.General?.directURL; if (url == null) return null; diff --git a/Wabbajack.Lib/Downloaders/DropboxDownloader.cs b/Wabbajack.Lib/Downloaders/DropboxDownloader.cs index 270b4299..0247b14e 100644 --- a/Wabbajack.Lib/Downloaders/DropboxDownloader.cs +++ b/Wabbajack.Lib/Downloaders/DropboxDownloader.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using System.Web; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs index b4b2ace7..b8dbdceb 100644 --- a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs @@ -4,7 +4,6 @@ using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Validation; using Game = Wabbajack.Common.Game; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs b/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs index db385314..26602978 100644 --- a/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs @@ -5,7 +5,6 @@ using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Exceptions; using Wabbajack.Lib.Validation; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs index 12455dca..912306a2 100644 --- a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs +++ b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs @@ -10,7 +10,6 @@ using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Exceptions; using Wabbajack.Lib.Validation; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/IDownloader.cs b/Wabbajack.Lib/Downloaders/IDownloader.cs index b43aef76..17ced7bc 100644 --- a/Wabbajack.Lib/Downloaders/IDownloader.cs +++ b/Wabbajack.Lib/Downloaders/IDownloader.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/INeedsLogin.cs b/Wabbajack.Lib/Downloaders/INeedsLogin.cs index d22a6f05..8ce03afe 100644 --- a/Wabbajack.Lib/Downloaders/INeedsLogin.cs +++ b/Wabbajack.Lib/Downloaders/INeedsLogin.cs @@ -2,7 +2,6 @@ using System.Reactive; using System.Security; using ReactiveUI; -#nullable enable namespace Wabbajack.Lib.Downloaders { @@ -12,7 +11,7 @@ namespace Wabbajack.Lib.Downloaders ReactiveCommand ClearLogin { get; } IObservable IsLoggedIn { get; } string SiteName { get; } - IObservable MetaInfo { get; } + IObservable? MetaInfo { get; } Uri SiteURL { get; } Uri? IconUri { get; } } diff --git a/Wabbajack.Lib/Downloaders/IUrlDownloader.cs b/Wabbajack.Lib/Downloaders/IUrlDownloader.cs index 7650e0e5..1b4384af 100644 --- a/Wabbajack.Lib/Downloaders/IUrlDownloader.cs +++ b/Wabbajack.Lib/Downloaders/IUrlDownloader.cs @@ -2,6 +2,6 @@ { public interface IUrlDownloader : IDownloader { - AbstractDownloadState GetDownloaderState(string url); + AbstractDownloadState? GetDownloaderState(string url); } } diff --git a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs index e1b7a06d..c319fb7a 100644 --- a/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs +++ b/Wabbajack.Lib/Downloaders/LoversLabDownloader.cs @@ -7,7 +7,6 @@ using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.WebAutomation; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/MEGADownloader.cs b/Wabbajack.Lib/Downloaders/MEGADownloader.cs index 02977628..e318a06a 100644 --- a/Wabbajack.Lib/Downloaders/MEGADownloader.cs +++ b/Wabbajack.Lib/Downloaders/MEGADownloader.cs @@ -8,7 +8,6 @@ using Newtonsoft.Json; using ReactiveUI; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/ManualDownloader.cs b/Wabbajack.Lib/Downloaders/ManualDownloader.cs index b9f4ba72..805ebc45 100644 --- a/Wabbajack.Lib/Downloaders/ManualDownloader.cs +++ b/Wabbajack.Lib/Downloaders/ManualDownloader.cs @@ -6,7 +6,6 @@ using Wabbajack.Common; using Wabbajack.Common.IO; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Validation; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs b/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs index c895002a..a9678fd8 100644 --- a/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs +++ b/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Wabbajack.Common; using Wabbajack.Lib.Validation; using Wabbajack.Lib.WebAutomation; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/ModDBDownloader.cs b/Wabbajack.Lib/Downloaders/ModDBDownloader.cs index 1a3b51fe..9d0022ae 100644 --- a/Wabbajack.Lib/Downloaders/ModDBDownloader.cs +++ b/Wabbajack.Lib/Downloaders/ModDBDownloader.cs @@ -6,7 +6,6 @@ using Newtonsoft.Json; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; using Wabbajack.Lib.Validation; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/NexusDownloader.cs b/Wabbajack.Lib/Downloaders/NexusDownloader.cs index fc4728d3..d6914624 100644 --- a/Wabbajack.Lib/Downloaders/NexusDownloader.cs +++ b/Wabbajack.Lib/Downloaders/NexusDownloader.cs @@ -12,7 +12,6 @@ using Wabbajack.Common.StatusFeed.Errors; using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.Validation; using Game = Wabbajack.Common.Game; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs b/Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs index 96cfadde..cdf1ad5a 100644 --- a/Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs +++ b/Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs @@ -14,20 +14,21 @@ namespace Wabbajack.Lib.Downloaders { public class SteamWorkshopDownloader : IUrlDownloader { - private SteamWorkshopItem _item; - - public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) + public async Task GetDownloaderState(dynamic archiveINI, bool quickMode) { var id = archiveINI?.General?.itemID; var steamID = archiveINI?.General?.steamID; var size = archiveINI?.General?.itemSize; - _item = new SteamWorkshopItem + if (steamID == null) + { + throw new ArgumentException("Steam workshop item had no steam ID."); + } + var item = new SteamWorkshopItem(GameRegistry.GetBySteamID(int.Parse(steamID))) { ItemID = id != null ? int.Parse(id) : 0, Size = size != null ? int.Parse(size) : 0, - Game = steamID != null ? GameRegistry.GetBySteamID(int.Parse(steamID)) : null }; - return new State {Item = _item}; + return new State(item); } public async Task Prepare() @@ -41,8 +42,14 @@ namespace Wabbajack.Lib.Downloaders public class State : AbstractDownloadState { - public SteamWorkshopItem Item { get; set; } - public override object[] PrimaryKey { get => new object[] {Item.Game, Item.ItemID}; } + public SteamWorkshopItem Item { get; } + + public override object[] PrimaryKey => new object[] { Item.Game, Item.ItemID }; + + public State(SteamWorkshopItem item) + { + Item = item; + } public override bool IsWhitelisted(ServerWhitelist whitelist) { diff --git a/Wabbajack.Lib/Downloaders/TESAllianceDownloader.cs b/Wabbajack.Lib/Downloaders/TESAllianceDownloader.cs index 16cf46cc..ae6a8fa1 100644 --- a/Wabbajack.Lib/Downloaders/TESAllianceDownloader.cs +++ b/Wabbajack.Lib/Downloaders/TESAllianceDownloader.cs @@ -1,7 +1,6 @@ using System; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/UrlDownloaders/BethesdaNetInferencer.cs b/Wabbajack.Lib/Downloaders/UrlDownloaders/BethesdaNetInferencer.cs index 2dfd3cf2..0ef367e1 100644 --- a/Wabbajack.Lib/Downloaders/UrlDownloaders/BethesdaNetInferencer.cs +++ b/Wabbajack.Lib/Downloaders/UrlDownloaders/BethesdaNetInferencer.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -#nullable enable namespace Wabbajack.Lib.Downloaders.UrlDownloaders { diff --git a/Wabbajack.Lib/Downloaders/UrlDownloaders/IUrlInferencer.cs b/Wabbajack.Lib/Downloaders/UrlDownloaders/IUrlInferencer.cs index 84be4335..9aaf73d7 100644 --- a/Wabbajack.Lib/Downloaders/UrlDownloaders/IUrlInferencer.cs +++ b/Wabbajack.Lib/Downloaders/UrlDownloaders/IUrlInferencer.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -#nullable enable namespace Wabbajack.Lib.Downloaders.UrlDownloaders { diff --git a/Wabbajack.Lib/Downloaders/UrlDownloaders/YoutubeInferencer.cs b/Wabbajack.Lib/Downloaders/UrlDownloaders/YoutubeInferencer.cs index 8c8d1974..c3f96716 100644 --- a/Wabbajack.Lib/Downloaders/UrlDownloaders/YoutubeInferencer.cs +++ b/Wabbajack.Lib/Downloaders/UrlDownloaders/YoutubeInferencer.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Threading.Tasks; using Wabbajack.Common; using YoutubeExplode; -#nullable enable namespace Wabbajack.Lib.Downloaders.UrlDownloaders { diff --git a/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs b/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs index f0cdafb8..8f7d1c5c 100644 --- a/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs +++ b/Wabbajack.Lib/Downloaders/VectorPlexusDownloader.cs @@ -1,6 +1,5 @@ using System; using Wabbajack.Common.Serialization.Json; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Downloaders/YouTubeDownloader.cs b/Wabbajack.Lib/Downloaders/YouTubeDownloader.cs index 4e6be90c..3f076305 100644 --- a/Wabbajack.Lib/Downloaders/YouTubeDownloader.cs +++ b/Wabbajack.Lib/Downloaders/YouTubeDownloader.cs @@ -15,7 +15,6 @@ using YoutubeExplode.Exceptions; using YoutubeExplode.Models.MediaStreams; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; -#nullable enable namespace Wabbajack.Lib.Downloaders { diff --git a/Wabbajack.Lib/Exceptions/HttpException.cs b/Wabbajack.Lib/Exceptions/HttpException.cs index 41d46b03..af0a3bb0 100644 --- a/Wabbajack.Lib/Exceptions/HttpException.cs +++ b/Wabbajack.Lib/Exceptions/HttpException.cs @@ -12,6 +12,5 @@ namespace Wabbajack.Lib.Exceptions Code = code; Reason = reason; } - } } diff --git a/Wabbajack.Lib/FileUploader/AuthorAPI.cs b/Wabbajack.Lib/FileUploader/AuthorAPI.cs index 149b4d35..638dc927 100644 --- a/Wabbajack.Lib/FileUploader/AuthorAPI.cs +++ b/Wabbajack.Lib/FileUploader/AuthorAPI.cs @@ -21,9 +21,9 @@ namespace Wabbajack.Lib.FileUploader { public static IObservable HaveAuthorAPIKey => Utils.HaveEncryptedJsonObservable(Consts.AuthorAPIKeyFile); - public static string ApiKeyOverride = null; + public static string? ApiKeyOverride = null; - public static async Task GetAPIKey(string apiKey = null) + public static async Task GetAPIKey(string? apiKey = null) { if (ApiKeyOverride != null) return ApiKeyOverride; return apiKey ?? (await Consts.LocalAppDataPath.Combine(Consts.AuthorAPIKeyFile).ReadAllTextAsync()).Trim(); @@ -32,7 +32,7 @@ namespace Wabbajack.Lib.FileUploader public static Uri UploadURL => new Uri($"{Consts.WabbajackBuildServerUri}upload_file"); public static long BLOCK_SIZE = (long)1024 * 1024 * 2; public static int MAX_CONNECTIONS = 8; - public static Task UploadFile(AbsolutePath filename, Action progressFn, string apikey=null) + public static Task UploadFile(AbsolutePath filename, Action progressFn, string? apikey = null) { var tcs = new TaskCompletionSource(); Task.Run(async () => @@ -123,7 +123,7 @@ namespace Wabbajack.Lib.FileUploader return tcs.Task; } - public static async Task GetAuthorizedClient(string apiKey=null) + public static async Task GetAuthorizedClient(string? apiKey = null) { var client = new Common.Http.Client(); client.Headers.Add(("X-API-KEY", await GetAPIKey(apiKey))); diff --git a/Wabbajack.Lib/IBatchProcessor.cs b/Wabbajack.Lib/IBatchProcessor.cs index e8f34b8c..ebf4531f 100644 --- a/Wabbajack.Lib/IBatchProcessor.cs +++ b/Wabbajack.Lib/IBatchProcessor.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using Wabbajack.Common; -#nullable enable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/LibCefHelpers/Init.cs b/Wabbajack.Lib/LibCefHelpers/Init.cs index 573fd9db..9f3c9985 100644 --- a/Wabbajack.Lib/LibCefHelpers/Init.cs +++ b/Wabbajack.Lib/LibCefHelpers/Init.cs @@ -78,10 +78,10 @@ namespace Wabbajack.Lib.LibCefHelpers [JsonName("HttpCookie")] public class Cookie { - public string Name { get; set; } - public string Value { get; set; } - public string Domain { get; set; } - public string Path { get; set; } + public string Name { get; set; } = string.Empty; + public string Value { get; set; } = string.Empty; + public string Domain { get; set; } = string.Empty; + public string Path { get; set; } = string.Empty; } public static void Init() diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 79181eaa..97b54ee7 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -20,7 +20,6 @@ using File = Alphaleonis.Win32.Filesystem.File; using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo; using Game = Wabbajack.Common.Game; using Path = Alphaleonis.Win32.Filesystem.Path; -#nullable enable namespace Wabbajack.Lib { @@ -175,9 +174,8 @@ namespace Wabbajack.Lib IndexedArchives = (await MO2DownloadsFolder.EnumerateFiles() .Where(f => f.WithExtension(Consts.MetaFileExtension).Exists) - .PMap(Queue, async f => new IndexedArchive + .PMap(Queue, async f => new IndexedArchive(VFS.Index.ByRootPath[f]) { - File = VFS.Index.ByRootPath[f], Name = (string)f.FileName, IniData = f.WithExtension(Consts.MetaFileExtension).LoadIniFile(), Meta = await f.WithExtension(Consts.MetaFileExtension).ReadAllTextAsync() diff --git a/Wabbajack.Lib/MO2Installer.cs b/Wabbajack.Lib/MO2Installer.cs index ab4af57a..6ca32b01 100644 --- a/Wabbajack.Lib/MO2Installer.cs +++ b/Wabbajack.Lib/MO2Installer.cs @@ -21,7 +21,6 @@ using Directory = Alphaleonis.Win32.Filesystem.Directory; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; using SectionData = Wabbajack.Common.SectionData; -#nullable enable namespace Wabbajack.Lib { @@ -332,6 +331,10 @@ namespace Wabbajack.Lib private void SetScreenSizeInPrefs() { + if (SystemParameters == null) + { + throw new ArgumentNullException("System Parameters was null. Cannot set screen size prefs"); + } var config = new IniParserConfiguration {AllowDuplicateKeys = true, AllowDuplicateSections = true}; foreach (var file in OutputFolder.Combine("profiles").EnumerateFiles() .Where(f => ((string)f.FileName).EndsWith("refs.ini"))) diff --git a/Wabbajack.Lib/Manifest.cs b/Wabbajack.Lib/Manifest.cs index 00ce5d6a..1aa4d846 100644 --- a/Wabbajack.Lib/Manifest.cs +++ b/Wabbajack.Lib/Manifest.cs @@ -2,7 +2,6 @@ using System.Linq; using Wabbajack.Common; using Wabbajack.Common.Serialization.Json; -#nullable enable namespace Wabbajack.Lib { @@ -42,12 +41,11 @@ namespace Wabbajack.Lib InstallSize = modlist.InstallSize; // meta is being omitted due to it being useless and not very space friendly - Archives = modlist.Archives.Select(a => new Archive + Archives = modlist.Archives.Select(a => new Archive(a.State) { Hash = a.Hash, Name = a.Name, Size = a.Size, - State = a.State }).ToList(); } } diff --git a/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs b/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs index e68df7e2..4bae4f76 100644 --- a/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs +++ b/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs @@ -13,13 +13,13 @@ namespace Wabbajack.Lib.ModListRegistry public class ModlistMetadata { [JsonProperty("title")] - public string Title { get; set; } + public string Title { get; set; } = string.Empty; [JsonProperty("description")] - public string Description { get; set; } + public string Description { get; set; } = string.Empty; [JsonProperty("author")] - public string Author { get; set; } + public string Author { get; set; } = string.Empty; [JsonProperty("game")] public Game Game { get; set; } @@ -33,7 +33,7 @@ namespace Wabbajack.Lib.ModListRegistry public LinksObject Links { get; set; } = new LinksObject(); [JsonProperty("download_metadata")] - public DownloadMetadata DownloadMetadata { get; set; } + public DownloadMetadata? DownloadMetadata { get; set; } [JsonIgnore] public ModListSummary ValidationSummary { get; set; } = new ModListSummary(); @@ -42,22 +42,18 @@ namespace Wabbajack.Lib.ModListRegistry public class LinksObject { [JsonProperty("image")] - public string ImageUri { get; set; } + public string ImageUri { get; set; } = string.Empty; [JsonProperty("readme")] - public string Readme { get; set; } + public string Readme { get; set; } = string.Empty; [JsonProperty("download")] - public string Download { get; set; } - + public string Download { get; set; } = string.Empty; + [JsonProperty("machineURL")] - public string MachineURL { get; set; } + public string MachineURL { get; set; } = string.Empty; } - - - - public static async Task> LoadFromGithub() { var client = new Common.Http.Client(); @@ -103,18 +99,17 @@ namespace Wabbajack.Lib.ModListRegistry public long SizeOfArchives { get; set; } public long NumberOfInstalledFiles { get; set; } public long SizeOfInstalledFiles { get; set; } - } [JsonName("ModListSummary")] public class ModListSummary { [JsonProperty("name")] - public string Name { get; set; } - + public string Name { get; set; } = string.Empty; + [JsonProperty("machineURL")] - public string MachineURL { get; set; } - + public string MachineURL { get; set; } = string.Empty; + [JsonProperty("checked")] public DateTime Checked { get; set; } [JsonProperty("failed")] diff --git a/Wabbajack.Lib/NexusApi/Dtos.cs b/Wabbajack.Lib/NexusApi/Dtos.cs index 3ffe2d4c..594cc1ad 100644 --- a/Wabbajack.Lib/NexusApi/Dtos.cs +++ b/Wabbajack.Lib/NexusApi/Dtos.cs @@ -4,57 +4,57 @@ namespace Wabbajack.Lib.NexusApi { public class UserStatus { - public string email; + public string email = string.Empty; public bool is_premium; public bool is_supporter; - public string key; - public string name; - public string profile_url; - public string user_id; + public string key = string.Empty; + public string name = string.Empty; + public string profile_url = string.Empty; + public string user_id = string.Empty; } public class NexusFileInfo { public long category_id { get; set; } - public string category_name { get; set; } - public string changelog_html { get; set; } - public string description { get; set; } - public string external_virus_scan_url { get; set; } + public string category_name { get; set; } = string.Empty; + public string changelog_html { get; set; } = string.Empty; + public string description { get; set; } = string.Empty; + public string external_virus_scan_url { get; set; } = string.Empty; public long file_id { get; set; } - public string file_name { get; set; } + public string file_name { get; set; } = string.Empty; public bool is_primary { get; set; } - public string mod_version { get; set; } - public string name { get; set; } + public string mod_version { get; set; } = string.Empty; + public string name { get; set; } = string.Empty; public long size { get; set; } public long size_kb { get; set; } public DateTime uploaded_time { get; set; } public long uploaded_timestamp { get; set; } - public string version { get; set; } + public string version { get; set; } = string.Empty; } public class ModInfo { public uint _internal_version { get; set; } - public string game_name { get; set; } - public string mod_id { get; set; } - public string name { get; set; } - public string summary { get; set; } - public string author { get; set; } - public string uploaded_by { get; set; } - public string uploaded_users_profile_url { get; set; } - public string picture_url { get; set; } + public string game_name { get; set; } = string.Empty; + public string mod_id { get; set; } = string.Empty; + public string name { get; set; } = string.Empty; + public string summary { get; set; } = string.Empty; + public string author { get; set; } = string.Empty; + public string uploaded_by { get; set; } = string.Empty; + public string uploaded_users_profile_url { get; set; } = string.Empty; + public string picture_url { get; set; } = string.Empty; public bool contains_adult_content { get; set; } } public class MD5Response { - public ModInfo mod; - public NexusFileInfo file_details; + public ModInfo? mod; + public NexusFileInfo? file_details; } public class EndorsementResponse { - public string message; - public string status; + public string message = string.Empty; + public string status = string.Empty; } } diff --git a/Wabbajack.Lib/NexusApi/NexusApi.cs b/Wabbajack.Lib/NexusApi/NexusApi.cs index eb5d486b..7ca855d8 100644 --- a/Wabbajack.Lib/NexusApi/NexusApi.cs +++ b/Wabbajack.Lib/NexusApi/NexusApi.cs @@ -27,12 +27,11 @@ namespace Wabbajack.Lib.NexusApi #region Authentication - public string ApiKey { get; } + public string? ApiKey { get; } public bool IsAuthenticated => ApiKey != null; - private Task _userStatus; - + private Task? _userStatus; public Task UserStatus { get @@ -214,7 +213,7 @@ namespace Wabbajack.Lib.NexusApi #endregion - private NexusApiClient(string apiKey = null) + private NexusApiClient(string? apiKey = null) { ApiKey = apiKey; @@ -230,9 +229,9 @@ namespace Wabbajack.Lib.NexusApi Directory.CreateDirectory(Consts.NexusCacheDirectory); } - public static async Task Get(string apiKey = null) + public static async Task Get(string? apiKey = null) { - apiKey = apiKey ?? await GetApiKey(); + apiKey ??= await GetApiKey(); return new NexusApiClient(apiKey); } @@ -316,9 +315,10 @@ namespace Wabbajack.Lib.NexusApi throw; } } + public class GetModFilesResponse { - public List files { get; set; } + public List files { get; set; } = new List(); } public async Task GetModFiles(Game game, long modid) @@ -344,18 +344,18 @@ namespace Wabbajack.Lib.NexusApi private class DownloadLink { - public string URI { get; set; } + public string URI { get; set; } = string.Empty; } - public static MethodInfo CacheMethod { get; set; } - - private static string _localCacheDir; + private static string? _localCacheDir; public static string LocalCacheDir { get { if (_localCacheDir == null) _localCacheDir = Environment.GetEnvironmentVariable("NEXUSCACHEDIR"); + if (_localCacheDir == null) + throw new ArgumentNullException($"Enviornment variable could not be located: NEXUSCACHEDIR"); return _localCacheDir; } set => _localCacheDir = value; diff --git a/Wabbajack.Lib/NexusApi/NexusApiUtils.cs b/Wabbajack.Lib/NexusApi/NexusApiUtils.cs index f29959e4..c75ecf78 100644 --- a/Wabbajack.Lib/NexusApi/NexusApiUtils.cs +++ b/Wabbajack.Lib/NexusApi/NexusApiUtils.cs @@ -19,15 +19,10 @@ namespace Wabbajack.Lib.NexusApi public static string FixupSummary(string argSummary) { - if (argSummary != null) - { - return argSummary.Replace("'", "'") - .Replace("
", "\n\n") - .Replace("
", "\n\n") - .Replace("!", "!"); - } - - return argSummary; + return argSummary.Replace("'", "'") + .Replace("
", "\n\n") + .Replace("
", "\n\n") + .Replace("!", "!"); } } } diff --git a/Wabbajack.Lib/NexusApi/RequestNexusAuthorization.cs b/Wabbajack.Lib/NexusApi/RequestNexusAuthorization.cs index bf17e3a3..a84c707e 100644 --- a/Wabbajack.Lib/NexusApi/RequestNexusAuthorization.cs +++ b/Wabbajack.Lib/NexusApi/RequestNexusAuthorization.cs @@ -10,7 +10,7 @@ namespace Wabbajack.Lib.NexusApi public class RequestNexusAuthorization : AUserIntervention { public override string ShortDescription => "Getting User's Nexus API Key"; - public override string ExtendedDescription { get; } + public override string ExtendedDescription { get; } = string.Empty; private readonly TaskCompletionSource _source = new TaskCompletionSource(); public Task Task => _source.Task; diff --git a/Wabbajack.Lib/StatusMessages/ConfirmUpdateOfExistingInstall.cs b/Wabbajack.Lib/StatusMessages/ConfirmUpdateOfExistingInstall.cs index d3e7db4f..6e65243d 100644 --- a/Wabbajack.Lib/StatusMessages/ConfirmUpdateOfExistingInstall.cs +++ b/Wabbajack.Lib/StatusMessages/ConfirmUpdateOfExistingInstall.cs @@ -10,7 +10,7 @@ namespace Wabbajack.Lib public class ConfirmUpdateOfExistingInstall : ConfirmationIntervention { public AbsolutePath OutputFolder { get; set; } - public string ModListName { get; set; } + public string ModListName { get; set; } = string.Empty; public override string ShortDescription { get; } = "Do you want to overwrite existing files?"; diff --git a/Wabbajack.Lib/StatusMessages/ManuallyDownloadFile.cs b/Wabbajack.Lib/StatusMessages/ManuallyDownloadFile.cs index a782e089..ee02101d 100644 --- a/Wabbajack.Lib/StatusMessages/ManuallyDownloadFile.cs +++ b/Wabbajack.Lib/StatusMessages/ManuallyDownloadFile.cs @@ -9,9 +9,9 @@ namespace Wabbajack.Lib public class ManuallyDownloadFile : AUserIntervention { public ManualDownloader.State State { get; } - public override string ShortDescription { get; } - public override string ExtendedDescription { get; } - + public override string ShortDescription { get; } = string.Empty; + public override string ExtendedDescription { get; } = string.Empty; + private TaskCompletionSource<(Uri, Common.Http.Client)> _tcs = new TaskCompletionSource<(Uri, Common.Http.Client)>(); public Task<(Uri, Common.Http.Client)> Task => _tcs.Task; diff --git a/Wabbajack.Lib/StatusMessages/ManuallyDownloadNexusFile.cs b/Wabbajack.Lib/StatusMessages/ManuallyDownloadNexusFile.cs index e403ab73..8637f1cb 100644 --- a/Wabbajack.Lib/StatusMessages/ManuallyDownloadNexusFile.cs +++ b/Wabbajack.Lib/StatusMessages/ManuallyDownloadNexusFile.cs @@ -9,9 +9,9 @@ namespace Wabbajack.Lib public class ManuallyDownloadNexusFile : AUserIntervention { public NexusDownloader.State State { get; } - public override string ShortDescription { get; } - public override string ExtendedDescription { get; } - + public override string ShortDescription { get; } = string.Empty; + public override string ExtendedDescription { get; } = string.Empty; + private TaskCompletionSource _tcs = new TaskCompletionSource(); public Task Task => _tcs.Task; diff --git a/Wabbajack.Lib/SystemParameters.cs b/Wabbajack.Lib/SystemParameters.cs index 2dc7c9d5..2f288894 100644 --- a/Wabbajack.Lib/SystemParameters.cs +++ b/Wabbajack.Lib/SystemParameters.cs @@ -1,5 +1,4 @@ using System; -#nullable enable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/Validation/DTOs.cs b/Wabbajack.Lib/Validation/DTOs.cs index 25a0741e..00be5104 100644 --- a/Wabbajack.Lib/Validation/DTOs.cs +++ b/Wabbajack.Lib/Validation/DTOs.cs @@ -10,33 +10,32 @@ namespace Wabbajack.Lib.Validation public bool? CanUseInOtherGames { get; set; } } - public class Author - { - public Permissions Permissions { get; set; } - public Dictionary Games; - } + //public class Author + //{ + // public Permissions Permissions { get; set; } + // public Dictionary Games; + //} - public class Game - { - public Permissions Permissions; - public Dictionary Mods; - } + //public class Game + //{ + // public Permissions Permissions; + // public Dictionary Mods; + //} - public class Mod - { - public Permissions Permissions; - public Dictionary Files; - } - - public class File - { - public Permissions Permissions; - } + //public class Mod + //{ + // public Permissions Permissions; + // public Dictionary Files; + //} + //public class File + //{ + // public Permissions Permissions; + //} public class ServerWhitelist { - public List GoogleIDs; - public List AllowedPrefixes; + public List GoogleIDs = new List(); + public List AllowedPrefixes = new List(); } } diff --git a/Wabbajack.Lib/ViewModel.cs b/Wabbajack.Lib/ViewModel.cs index ce5da622..719a7ccc 100644 --- a/Wabbajack.Lib/ViewModel.cs +++ b/Wabbajack.Lib/ViewModel.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Reactive.Disposables; using System.Runtime.CompilerServices; -#nullable enable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/VortexCompiler.cs b/Wabbajack.Lib/VortexCompiler.cs index 8f0e3022..4ad94116 100644 --- a/Wabbajack.Lib/VortexCompiler.cs +++ b/Wabbajack.Lib/VortexCompiler.cs @@ -15,7 +15,6 @@ using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.Validation; using File = Alphaleonis.Win32.Filesystem.File; using Game = Wabbajack.Common.Game; -#nullable enable namespace Wabbajack.Lib { diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index b79980e0..9b204559 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -1,9 +1,10 @@  - netcoreapp3.1 - x64 - win10-x64 + netcoreapp3.1 + x64 + win10-x64 + enable diff --git a/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs b/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs index 513d3008..48e73d50 100644 --- a/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs +++ b/Wabbajack.Lib/WebAutomation/CefSharpWrapper.cs @@ -13,8 +13,8 @@ namespace Wabbajack.Lib.WebAutomation { public class CefSharpWrapper : IWebDriver { - private IWebBrowser _browser; - public Action DownloadHandler { get; set; } + private readonly IWebBrowser _browser; + public Action? DownloadHandler { get; set; } public CefSharpWrapper(IWebBrowser browser) { _browser = browser; @@ -24,7 +24,7 @@ namespace Wabbajack.Lib.WebAutomation { var tcs = new TaskCompletionSource(); - EventHandler handler = null; + EventHandler? handler = null; handler = (sender, e) => { if (!e.IsLoading) @@ -68,7 +68,7 @@ namespace Wabbajack.Lib.WebAutomation public class PopupBlocker : ILifeSpanHandler { - private CefSharpWrapper _wrapper; + private readonly CefSharpWrapper _wrapper; public PopupBlocker(CefSharpWrapper cefSharpWrapper) { @@ -77,7 +77,7 @@ namespace Wabbajack.Lib.WebAutomation public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, - IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser) + IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser? newBrowser) { // Block popups newBrowser = null; @@ -86,7 +86,6 @@ namespace Wabbajack.Lib.WebAutomation public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser) { - } public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser) @@ -96,7 +95,6 @@ namespace Wabbajack.Lib.WebAutomation public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser) { - } } @@ -112,7 +110,7 @@ namespace Wabbajack.Lib.WebAutomation public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback) { - _wrapper.DownloadHandler(new Uri(downloadItem.Url)); + _wrapper.DownloadHandler?.Invoke(new Uri(downloadItem.Url)); } public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, diff --git a/Wabbajack.Lib/WebAutomation/IWebDriver.cs b/Wabbajack.Lib/WebAutomation/IWebDriver.cs index 0672aef5..529a04cb 100644 --- a/Wabbajack.Lib/WebAutomation/IWebDriver.cs +++ b/Wabbajack.Lib/WebAutomation/IWebDriver.cs @@ -13,6 +13,6 @@ namespace Wabbajack.Lib.WebAutomation Task NavigateTo(Uri uri); Task EvaluateJavaScript(string text); Task GetCookies(string domainPrefix); - public Action DownloadHandler { get; set; } + public Action? DownloadHandler { get; set; } } } diff --git a/Wabbajack.Lib/WebAutomation/WebAutomation.cs b/Wabbajack.Lib/WebAutomation/WebAutomation.cs index 09eba17a..d906c968 100644 --- a/Wabbajack.Lib/WebAutomation/WebAutomation.cs +++ b/Wabbajack.Lib/WebAutomation/WebAutomation.cs @@ -24,13 +24,13 @@ namespace Wabbajack.Lib.WebAutomation return driver; } - public async Task NavigateTo(Uri uri) + public async Task NavigateTo(Uri uri) { await _driver.NavigateTo(uri); return await GetLocation(); } - public async ValueTask GetLocation() + public async ValueTask GetLocation() { try { diff --git a/Wabbajack.Lib/zEditIntegration.cs b/Wabbajack.Lib/zEditIntegration.cs index 5590ddf8..ba2d1845 100644 --- a/Wabbajack.Lib/zEditIntegration.cs +++ b/Wabbajack.Lib/zEditIntegration.cs @@ -9,7 +9,6 @@ using Directory = Alphaleonis.Win32.Filesystem.Directory; using File = Alphaleonis.Win32.Filesystem.File; using Path = Alphaleonis.Win32.Filesystem.Path; using System.Threading.Tasks; -#nullable enable namespace Wabbajack.Lib { @@ -151,7 +150,7 @@ namespace Wabbajack.Lib return inline; } var result = source.EvolveTo(); - result.Sources = merge.plugins.Select(f => + result.Sources.SetTo(merge.plugins.Select(f => { var origPath = (AbsolutePath)Path.Combine(f.dataFolder, f.filename); var paths = new[] @@ -172,10 +171,11 @@ namespace Wabbajack.Lib try { hash = _compiler.VFS.Index.ByRootPath[absPath].Hash; - } catch (KeyNotFoundException e) + } + catch (KeyNotFoundException e) { - Utils.ErrorThrow(e, $"Could not find the key {absPath} in the VFS Index dictionary!"); - return null; + Utils.Error(e, $"Could not find the key {absPath} in the VFS Index dictionary!"); + throw; } return new SourcePatch @@ -183,7 +183,7 @@ namespace Wabbajack.Lib RelativePath = absPath.RelativeTo(_mo2Compiler.MO2Folder), Hash = hash }; - }).ToList(); + })); var srcData = result.Sources.Select(f => _mo2Compiler.MO2Folder.Combine(f.RelativePath).ReadAllBytes()) .ConcatArrays(); diff --git a/Wabbajack.Test/ContentRightsManagementTests.cs b/Wabbajack.Test/ContentRightsManagementTests.cs index 0d915da4..7da956cc 100644 --- a/Wabbajack.Test/ContentRightsManagementTests.cs +++ b/Wabbajack.Test/ContentRightsManagementTests.cs @@ -48,15 +48,15 @@ namespace Wabbajack.Test GameType = Game.Skyrim, Archives = new List { - new Archive - { - State = new NexusDownloader.State + new Archive( + new NexusDownloader.State { Game = Game.Skyrim, Author = "bill", ModID = 42, FileID = 33, - }, + }) + { Hash = Hash.FromLong(42) } }, @@ -71,9 +71,8 @@ namespace Wabbajack.Test }; // Error due to file downloaded from 3rd party modlist.GameType = Game.Skyrim; - modlist.Archives[0] = new Archive() + modlist.Archives[0] = new Archive(new HTTPDownloader.State("https://somebadplace.com")) { - State = new HTTPDownloader.State("https://somebadplace.com"), Hash = Hash.FromLong(42) }; var errors = await validate.Validate(modlist); @@ -81,9 +80,8 @@ namespace Wabbajack.Test // Ok due to file downloaded from whitelisted 3rd party modlist.GameType = Game.Skyrim; - modlist.Archives[0] = new Archive + modlist.Archives[0] = new Archive(new HTTPDownloader.State("https://somegoodplace.com/baz.7z")) { - State = new HTTPDownloader.State("https://somegoodplace.com/baz.7z"), Hash = Hash.FromLong(42) }; errors = await validate.Validate(modlist); @@ -92,9 +90,8 @@ namespace Wabbajack.Test // Error due to file downloaded from bad 3rd party modlist.GameType = Game.Skyrim; - modlist.Archives[0] = new Archive + modlist.Archives[0] = new Archive(new GoogleDriveDownloader.State("bleg")) { - State = new GoogleDriveDownloader.State("bleg"), Hash = Hash.FromLong(42) }; errors = await validate.Validate(modlist); @@ -102,9 +99,8 @@ namespace Wabbajack.Test // Ok due to file downloaded from good google site modlist.GameType = Game.Skyrim; - modlist.Archives[0] = new Archive + modlist.Archives[0] = new Archive(new GoogleDriveDownloader.State("googleDEADBEEF")) { - State = new GoogleDriveDownloader.State("googleDEADBEEF"), Hash = Hash.FromLong(42) }; errors = await validate.Validate(modlist); diff --git a/Wabbajack.Test/DownloaderTests.cs b/Wabbajack.Test/DownloaderTests.cs index 08614e99..b6787fe1 100644 --- a/Wabbajack.Test/DownloaderTests.cs +++ b/Wabbajack.Test/DownloaderTests.cs @@ -67,13 +67,13 @@ namespace Wabbajack.Test var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!){Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist {AllowedPrefixes = new List{"https://mega.nz/#!CsMSFaaJ!-uziC4mbJPRy2e4pPk8Gjb3oDT_38Be9fzZ6Ld4NL-k" } })); Assert.False(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List{ "blerg" }})); - await converted.Download(new Archive {Name = "MEGA Test.txt"}, filename.Path); + await converted.Download(new Archive(state: null!) {Name = "MEGA Test.txt"}, filename.Path); Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), await filename.Path.FileHashAsync()); @@ -97,13 +97,13 @@ namespace Wabbajack.Test ((HTTPDownloader.State)url_state).Url); var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!){Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List { "https://www.dropbox.com/s/5hov3m2pboppoc2/WABBAJACK_TEST_FILE.txt?" } })); Assert.False(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List { "blerg" } })); - await converted.Download(new Archive { Name = "MEGA Test.txt" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "MEGA Test.txt" }, filename.Path); Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), await filename.Path.FileHashAsync()); @@ -127,13 +127,13 @@ namespace Wabbajack.Test ((GoogleDriveDownloader.State)url_state).Id); var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist { GoogleIDs = new List { "1grLRTrpHxlg7VPxATTFNfq2OkU_Plvh_" } })); Assert.False(converted.IsWhitelisted(new ServerWhitelist { GoogleIDs = new List()})); - await converted.Download(new Archive { Name = "MEGA Test.txt" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "MEGA Test.txt" }, filename.Path); Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), await filename.Path.FileHashAsync()); @@ -156,13 +156,13 @@ namespace Wabbajack.Test ((HTTPDownloader.State)url_state).Url); var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List { "http://build.wabbajack.org/" } })); Assert.False(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); - await converted.Download(new Archive { Name = "MEGA Test.txt" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "MEGA Test.txt" }, filename.Path); Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), await filename.Path.FileHashAsync()); @@ -180,7 +180,7 @@ namespace Wabbajack.Test Assert.NotNull(state); var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List { "http://build.wabbajack.org/" } })); @@ -226,37 +226,27 @@ namespace Wabbajack.Test [Fact] public async Task NexusDownload() { - var old_val = NexusApiClient.CacheMethod; - try - { - NexusApiClient.CacheMethod = null; - var ini = @"[General] + var ini = @"[General] gameName=SkyrimSE modID = 12604 fileID=35407"; - var state = (AbstractDownloadState)await DownloadDispatcher.ResolveArchive(ini.LoadIniString()); + var state = (AbstractDownloadState)await DownloadDispatcher.ResolveArchive(ini.LoadIniString()); - Assert.NotNull(state); + Assert.NotNull(state); - var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); - // Exercise the cache code - Assert.True(await converted.Verify(new Archive{Size = 20})); - using var filename = new TempFile(); + var converted = RoundTripState(state); + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20 })); + // Exercise the cache code + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20 })); + using var filename = new TempFile(); - Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List () })); + Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); - await converted.Download(new Archive { Name = "SkyUI.7z" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "SkyUI.7z" }, filename.Path); - Assert.Equal(Hash.FromBase64("dF2yafV2Oks="),await filename.Path.FileHashAsync()); - - } - finally - { - NexusApiClient.CacheMethod = old_val; - } + Assert.Equal(Hash.FromBase64("dF2yafV2Oks="), await filename.Path.FileHashAsync()); } [Fact] @@ -276,12 +266,12 @@ namespace Wabbajack.Test ((ModDBDownloader.State)url_state).Url); var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); - await converted.Download(new Archive { Name = "moddbtest.7z" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "moddbtest.7z" }, filename.Path); Assert.Equal(Hash.FromBase64("2lZt+1h6wxM="), await filename.Path.FileHashAsync()); } @@ -302,12 +292,12 @@ namespace Wabbajack.Test ((HTTPDownloader.State)url_state).Url); */ var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); - await converted.Download(new Archive { Name = "LoversLab Test.txt" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "LoversLab Test.txt" }, filename.Path); Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), await filename.Path.FileHashAsync()); @@ -330,12 +320,12 @@ namespace Wabbajack.Test ((HTTPDownloader.State)url_state).Url); */ var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); - await converted.Download(new Archive { Name = "Vector Plexus Test.zip" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "Vector Plexus Test.zip" }, filename.Path); Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), await filename.Path.FileHashAsync()); @@ -355,12 +345,12 @@ namespace Wabbajack.Test Assert.NotNull(state); var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); - await converted.Download(new Archive { Name = "TESAlliance Test.zip" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "TESAlliance Test.zip" }, filename.Path); Assert.Equal(Hash.FromBase64("eSIyd+KOG3s="), await filename.Path.FileHashAsync()); @@ -407,12 +397,12 @@ namespace Wabbajack.Test Assert.NotNull(state); var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive{Size = 20})); + Assert.True(await converted.Verify(new Archive(state: null!) { Size = 20})); using var filename = new TempFile(); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); - await converted.Download(new Archive { Name = "Update.esm" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "Update.esm" }, filename.Path); Assert.Equal(Hash.FromBase64("/DLG/LjdGXI="), await Utils.FileHashAsync(filename.Path)); Assert.Equal(await filename.Path.ReadAllBytesAsync(), await Game.SkyrimSpecialEdition.MetaData().GameLocation().Combine("Data/Update.esm").ReadAllBytesAsync()); @@ -434,11 +424,11 @@ namespace Wabbajack.Test Assert.NotNull(state); var converted = state.ViaJSON(); - Assert.True(await converted.Verify(new Archive {Name = "mod.ckm"})); + Assert.True(await converted.Verify(new Archive(state: null!) { Name = "mod.ckm"})); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); - await converted.Download(new Archive { Name = "mod.zip" }, filename.Path); + await converted.Download(new Archive(state: null!) { Name = "mod.zip" }, filename.Path); await using var fs = filename.Path.OpenRead(); using var archive = new ZipArchive(fs); @@ -463,12 +453,12 @@ namespace Wabbajack.Test var converted = RoundTripState(state); - Assert.True(await converted.Verify(new Archive {Name = "yt_test.zip"})); + Assert.True(await converted.Verify(new Archive(state: null!) { Name = "yt_test.zip"})); Assert.True(converted.IsWhitelisted(new ServerWhitelist { AllowedPrefixes = new List() })); using var tempFile = new TempFile(); - await converted.Download(new Archive {Name = "yt_test.zip"}, tempFile.Path); + await converted.Download(new Archive(state: null!) { Name = "yt_test.zip"}, tempFile.Path); Assert.Equal(Hash.FromBase64("kD36zbA2X9Q="), await tempFile.Path.FileHashAsync()); } @@ -497,12 +487,12 @@ namespace Wabbajack.Test var archivesa = new List() { - new Archive {Hash = statea.Hash, Name = "Download.esm", State = statea} + new Archive(statea) {Hash = statea.Hash, Name = "Download.esm" } }; var archivesb = new List() { - new Archive {Hash = stateb.Hash, Name = "Download.esm", State = stateb} + new Archive(stateb) {Hash = stateb.Hash, Name = "Download.esm" } }; var folder = ((RelativePath)"DownloadTests").RelativeToEntryPoint(); @@ -537,16 +527,16 @@ namespace Wabbajack.Test { await using var folder = new TempFolder(); var dest = folder.Dir.Combine("Cori.7z"); - var archive = new Archive - { - Name = "Cori.7z", - Hash = Hash.FromBase64("gCRVrvzDNH0="), - State = new NexusDownloader.State + var archive = new Archive( + new NexusDownloader.State { Game = Game.SkyrimSpecialEdition, ModID = 24808, FileID = 123501 - } + }) + { + Name = "Cori.7z", + Hash = Hash.FromBase64("gCRVrvzDNH0="), }; Assert.True(await DownloadDispatcher.DownloadWithPossibleUpgrade(archive, dest)); Assert.Equal(Hash.FromBase64("gCRVrvzDNH0="), await dest.FileHashCachedAsync()); diff --git a/Wabbajack.Test/EndToEndTests.cs b/Wabbajack.Test/EndToEndTests.cs index 70caa696..d71c4cae 100644 --- a/Wabbajack.Test/EndToEndTests.cs +++ b/Wabbajack.Test/EndToEndTests.cs @@ -97,7 +97,7 @@ namespace Wabbajack.Test if (!src.Exists) { var state = DownloadDispatcher.ResolveArchive(url); - await state.Download(new Archive { Name = "Unknown"}, src); + await state.Download(new Archive(state: null!) { Name = "Unknown"}, src); } utils.DownloadsFolder.CreateDirectory(); diff --git a/Wabbajack.Test/ModlistMetadataTests.cs b/Wabbajack.Test/ModlistMetadataTests.cs index f05f8ef2..6facd767 100644 --- a/Wabbajack.Test/ModlistMetadataTests.cs +++ b/Wabbajack.Test/ModlistMetadataTests.cs @@ -26,7 +26,7 @@ namespace Wabbajack.Test { var logoState = DownloadDispatcher.ResolveArchive(modlist.ImageUri); Assert.NotNull(logoState); - Assert.True(await logoState.Verify(new Archive{Size = 0}), $"{modlist.ImageUri} is not valid"); + Assert.True(await logoState.Verify(new Archive(state: null){Size = 0}), $"{modlist.ImageUri} is not valid"); } } diff --git a/Wabbajack/View Models/Gallery/ModListMetadataVM.cs b/Wabbajack/View Models/Gallery/ModListMetadataVM.cs index 1decb1b4..4eb1a17f 100644 --- a/Wabbajack/View Models/Gallery/ModListMetadataVM.cs +++ b/Wabbajack/View Models/Gallery/ModListMetadataVM.cs @@ -155,7 +155,7 @@ namespace Wabbajack try { var downloader = DownloadDispatcher.ResolveArchive(Metadata.Links.Download); - var result = await downloader.Download(new Archive { Name = Metadata.Title, Size = Metadata.DownloadMetadata?.Size ?? 0 }, Location); + var result = await downloader.Download(new Archive(state: null!) { Name = Metadata.Title, Size = Metadata.DownloadMetadata?.Size ?? 0 }, Location); // Want to rehash to current file, even if failed? Location.FileHashCached(); tcs.SetResult(result); From 165b857709e5c5c304b157ea6184217425f90ccc Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Fri, 10 Apr 2020 14:33:09 -0500 Subject: [PATCH 12/23] WabbajackTest.TestUtils calls await on directory deletion --- Wabbajack.Common/Json.cs | 4 +--- Wabbajack.Test/ACompilerTest.cs | 2 +- Wabbajack.Test/EndToEndTests.cs | 1 + Wabbajack.Test/TestUtils.cs | 13 ++++++------- .../VirtualFileSystemTests.cs | 14 +++++++------- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/Wabbajack.Common/Json.cs b/Wabbajack.Common/Json.cs index 4d2584c7..01a07fc3 100644 --- a/Wabbajack.Common/Json.cs +++ b/Wabbajack.Common/Json.cs @@ -78,10 +78,8 @@ namespace Wabbajack.Common using var tr = new StreamReader(stream, Encoding.UTF8, leaveOpen: true); using var reader = new JsonTextReader(tr); var ser = JsonSerializer.Create(JsonSettings); - return ser.Deserialize(reader); + return ser.Deserialize(reader)!; } - - private class HashJsonConverter : JsonConverter { diff --git a/Wabbajack.Test/ACompilerTest.cs b/Wabbajack.Test/ACompilerTest.cs index c980b234..a48d50a4 100644 --- a/Wabbajack.Test/ACompilerTest.cs +++ b/Wabbajack.Test/ACompilerTest.cs @@ -28,7 +28,7 @@ namespace Wabbajack.Test public override void Dispose() { - utils.Dispose(); + utils.DisposeAsync().AsTask().Wait(); _unsub.Dispose(); base.Dispose(); } diff --git a/Wabbajack.Test/EndToEndTests.cs b/Wabbajack.Test/EndToEndTests.cs index 70caa696..9ad82fb8 100644 --- a/Wabbajack.Test/EndToEndTests.cs +++ b/Wabbajack.Test/EndToEndTests.cs @@ -39,6 +39,7 @@ namespace Wabbajack.Test { Queue.Dispose(); _unsub.Dispose(); + utils.DisposeAsync().AsTask().Wait(); base.Dispose(); } diff --git a/Wabbajack.Test/TestUtils.cs b/Wabbajack.Test/TestUtils.cs index 5efdb7a1..0081c560 100644 --- a/Wabbajack.Test/TestUtils.cs +++ b/Wabbajack.Test/TestUtils.cs @@ -14,7 +14,7 @@ using Path = Alphaleonis.Win32.Filesystem.Path; namespace Wabbajack.Test { - public class TestUtils : IDisposable + public class TestUtils : IAsyncDisposable { private static Random _rng = new Random(); public TestUtils() @@ -119,13 +119,14 @@ namespace Wabbajack.Test return arr; } - public void Dispose() + public async ValueTask DisposeAsync() { - var exts = new [] {".md", ".exe"}; - WorkingDirectory.Combine(ID).DeleteDirectory(); + var exts = new[] { ".md", ".exe" }; + await WorkingDirectory.Combine(ID).DeleteDirectory(); Profiles.Do(p => { - foreach (var ext in exts) { + foreach (var ext in exts) + { var path = Path.Combine(Directory.GetCurrentDirectory(), p + ext); if (File.Exists(path)) File.Delete(path); @@ -246,7 +247,5 @@ namespace Wabbajack.Test GenerateRandomFileData(fullPath, i); return fullPath; } - - } } diff --git a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs index eca1b235..b5ae80f4 100644 --- a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs +++ b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs @@ -56,7 +56,7 @@ namespace Wabbajack.VirtualFileSystem.Test public async Task ArchiveContentsAreIndexed() { await AddFile(ARCHIVE_TEST_TXT, "This is a test"); - ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); + await ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); await AddTestRoot(); var absPath = "test.zip".RelativeTo(VFS_TEST_DIR); @@ -78,7 +78,7 @@ namespace Wabbajack.VirtualFileSystem.Test public async Task DuplicateFileHashes() { await AddFile(ARCHIVE_TEST_TXT, "This is a test"); - ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); + await ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); await AddFile(TEST_TXT, "This is a test"); await AddTestRoot(); @@ -127,7 +127,7 @@ namespace Wabbajack.VirtualFileSystem.Test public async Task CanStageSimpleArchives() { await AddFile(ARCHIVE_TEST_TXT, "This is a test"); - ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); + await ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); await AddTestRoot(); var res = new FullPath(TEST_ZIP, new[] {(RelativePath)"test.txt"}); @@ -143,12 +143,12 @@ namespace Wabbajack.VirtualFileSystem.Test public async Task CanStageNestedArchives() { await AddFile(ARCHIVE_TEST_TXT, "This is a test"); - ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); + await ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); var inner_dir = @"archive\other\dir".RelativeTo(VFS_TEST_DIR); inner_dir.CreateDirectory(); TEST_ZIP.MoveTo( @"archive\other\dir\nested.zip".RelativeTo(VFS_TEST_DIR)); - ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); + await ZipUpFolder(ARCHIVE_TEST_TXT.Parent, TEST_ZIP); await AddTestRoot(); @@ -168,10 +168,10 @@ namespace Wabbajack.VirtualFileSystem.Test await filename.WriteAllTextAsync(text); } - private static void ZipUpFolder(AbsolutePath folder, AbsolutePath output) + private static async Task ZipUpFolder(AbsolutePath folder, AbsolutePath output) { ZipFile.CreateFromDirectory((string)folder, (string)output); - folder.DeleteDirectory(); + await folder.DeleteDirectory(); } } } From f8d692afd09ec724275c4a18728be7314b4d669b Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Fri, 10 Apr 2020 14:35:47 -0500 Subject: [PATCH 13/23] Added async factory to VFSTests, so deletion can be awaited --- .../VirtualFileSystemTests.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs index b5ae80f4..001dba00 100644 --- a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs +++ b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs @@ -20,16 +20,21 @@ namespace Wabbajack.VirtualFileSystem.Test private readonly ITestOutputHelper _helper; private WorkQueue Queue { get; } - public VFSTests(ITestOutputHelper helper) + private VFSTests(ITestOutputHelper helper) { _helper = helper; Utils.LogMessages.Subscribe(f => _helper.WriteLine(f.ShortDescription)); - VFS_TEST_DIR.DeleteDirectory(); - VFS_TEST_DIR.CreateDirectory(); Queue = new WorkQueue(); context = new Context(Queue); } + public static async Task Factory(ITestOutputHelper helper) + { + await VFS_TEST_DIR.DeleteDirectory(); + VFS_TEST_DIR.CreateDirectory(); + return new VFSTests(helper); + } + [Fact] public async Task FilesAreIndexed() { From 69f18f2e222d585e822d9e544f0d5b150fc9da8f Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Fri, 10 Apr 2020 14:44:36 -0500 Subject: [PATCH 14/23] Context.Stage's return action swapped to Func So that its internal delete directory call can be awaited --- Wabbajack.Lib/AInstaller.cs | 2 +- Wabbajack.Lib/MO2Compiler.cs | 2 +- .../VirtualFileSystemTests.cs | 4 +-- Wabbajack.VirtualFileSystem/Context.cs | 31 ++++++++++++++----- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index 497ffd33..fd3b6292 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -177,7 +177,7 @@ namespace Wabbajack.Lib }); Status("Unstaging files"); - onFinish(); + await onFinish(); // Now patch all the files from this archive await grouping.OfType() diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 4ddc87ca..af0145eb 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -450,7 +450,7 @@ namespace Wabbajack.Lib private async Task BuildArchivePatches(Hash archiveSha, IEnumerable group, Dictionary absolutePaths) { - using var files = await VFS.StageWith(@group.Select(g => VFS.Index.FileForArchiveHashPath(g.ArchiveHashPath))); + await using var files = await VFS.StageWith(@group.Select(g => VFS.Index.FileForArchiveHashPath(g.ArchiveHashPath))); var byPath = files.GroupBy(f => string.Join("|", f.FilesInFullPath.Skip(1).Select(i => i.Name))) .ToDictionary(f => f.Key, f => f.First()); // Now Create the patches diff --git a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs index 001dba00..b54b812a 100644 --- a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs +++ b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs @@ -141,7 +141,7 @@ namespace Wabbajack.VirtualFileSystem.Test var cleanup = await context.Stage(new List {file}); Assert.Equal("This is a test", await file.StagedPath.ReadAllTextAsync()); - cleanup(); + await cleanup(); } [Fact] @@ -164,7 +164,7 @@ namespace Wabbajack.VirtualFileSystem.Test foreach (var file in files) Assert.Equal("This is a test", await file.StagedPath.ReadAllTextAsync()); - cleanup(); + await cleanup(); } private static async Task AddFile(AbsolutePath filename, string text) diff --git a/Wabbajack.VirtualFileSystem/Context.cs b/Wabbajack.VirtualFileSystem/Context.cs index 2d42769b..5105d83d 100644 --- a/Wabbajack.VirtualFileSystem/Context.cs +++ b/Wabbajack.VirtualFileSystem/Context.cs @@ -195,7 +195,7 @@ namespace Wabbajack.VirtualFileSystem } } - public async Task Stage(IEnumerable files) + public async Task> Stage(IEnumerable files) { var grouped = files.SelectMany(f => f.FilesInFullPath) .Distinct() @@ -215,18 +215,18 @@ namespace Wabbajack.VirtualFileSystem file.StagedPath = file.RelativeName.RelativeTo(tmpPath); } - return () => + return async () => { - paths.Do(p => + foreach (var p in paths) { - p.DeleteDirectory(); - }); + await p.DeleteDirectory(); + } }; } - public async Task> StageWith(IEnumerable files) + public async Task> StageWith(IEnumerable files) { - return new DisposableList(await Stage(files), files); + return new AsyncDisposableList(await Stage(files), files); } @@ -275,7 +275,7 @@ namespace Wabbajack.VirtualFileSystem _knownFiles = new List(); } - + #endregion } @@ -294,6 +294,21 @@ namespace Wabbajack.VirtualFileSystem } } + public class AsyncDisposableList : List, IAsyncDisposable + { + private Func _unstage; + + public AsyncDisposableList(Func unstage, IEnumerable files) : base(files) + { + _unstage = unstage; + } + + public async ValueTask DisposeAsync() + { + await _unstage(); + } + } + public class IndexRoot { public static IndexRoot Empty = new IndexRoot(); From 3f8f83e027f790d5f759d79eb59bcc22d1cfbf8d Mon Sep 17 00:00:00 2001 From: Timothy Baldridge Date: Fri, 10 Apr 2020 22:22:10 -0600 Subject: [PATCH 15/23] Update VirtualFileSystemTests.cs --- Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs index b54b812a..12e27073 100644 --- a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs +++ b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs @@ -20,7 +20,7 @@ namespace Wabbajack.VirtualFileSystem.Test private readonly ITestOutputHelper _helper; private WorkQueue Queue { get; } - private VFSTests(ITestOutputHelper helper) + public VFSTests(ITestOutputHelper helper) { _helper = helper; Utils.LogMessages.Subscribe(f => _helper.WriteLine(f.ShortDescription)); From 24ef0a74a526033406a27f8e0446eef6cca9453b Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sat, 11 Apr 2020 14:00:52 -0500 Subject: [PATCH 16/23] VirtualFileSystemTests utilize xUnit IAsyncLifetime --- .../VirtualFileSystemTests.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs index 12e27073..5059fbf8 100644 --- a/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs +++ b/Wabbajack.VirtualFileSystem.Test/VirtualFileSystemTests.cs @@ -9,7 +9,7 @@ using Xunit.Abstractions; namespace Wabbajack.VirtualFileSystem.Test { - public class VFSTests + public class VFSTests : IAsyncLifetime { private static readonly AbsolutePath VFS_TEST_DIR = "vfs_test_dir".ToPath().RelativeToEntryPoint(); private static readonly AbsolutePath TEST_ZIP = "test.zip".RelativeTo(VFS_TEST_DIR); @@ -18,21 +18,24 @@ namespace Wabbajack.VirtualFileSystem.Test private Context context; private readonly ITestOutputHelper _helper; - private WorkQueue Queue { get; } + private WorkQueue Queue { get; } = new WorkQueue(); public VFSTests(ITestOutputHelper helper) { _helper = helper; Utils.LogMessages.Subscribe(f => _helper.WriteLine(f.ShortDescription)); - Queue = new WorkQueue(); context = new Context(Queue); } - public static async Task Factory(ITestOutputHelper helper) + public async Task InitializeAsync() { await VFS_TEST_DIR.DeleteDirectory(); VFS_TEST_DIR.CreateDirectory(); - return new VFSTests(helper); + } + + public async Task DisposeAsync() + { + await VFS_TEST_DIR.DeleteDirectory(); } [Fact] @@ -56,7 +59,6 @@ namespace Wabbajack.VirtualFileSystem.Test await context.IntegrateFromFile( "vfs_cache.bin".RelativeTo(VFS_TEST_DIR)); } - [Fact] public async Task ArchiveContentsAreIndexed() { From 14a2285b73d277402bd8d9977d400ef61287696a Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sun, 12 Apr 2020 00:43:05 -0500 Subject: [PATCH 17/23] Merge fixes --- Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs b/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs index 164d2250..1732a4f9 100644 --- a/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs +++ b/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs @@ -65,7 +65,8 @@ namespace Wabbajack.Lib.NexusApi } return null; - }).Where(v => v != null); + }) + .NotNull(); } From 64c2780a6ff99b8dc0d7d3c420aa7785a249271f Mon Sep 17 00:00:00 2001 From: erri120 Date: Sun, 12 Apr 2020 18:06:37 +0200 Subject: [PATCH 18/23] Smaller JSON fixes --- Wabbajack.Common/Json.cs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/Wabbajack.Common/Json.cs b/Wabbajack.Common/Json.cs index 69916c2d..eadddc4f 100644 --- a/Wabbajack.Common/Json.cs +++ b/Wabbajack.Common/Json.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.IO; using System.Linq; using System.Reflection; using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Wabbajack.Common.Serialization.Json; @@ -19,7 +17,7 @@ namespace Wabbajack.Common { new HashJsonConverter(), new RelativePathConverter(), - new AbolutePathConverter(), + new AbsolutePathConverter(), new HashRelativePathConverter(), new FullPathConverter(), new GameConverter(), @@ -33,7 +31,7 @@ namespace Wabbajack.Common Converters = Converters}; public static JsonSerializerSettings GenericJsonSettings => - new JsonSerializerSettings { }; + new JsonSerializerSettings(); public static void ToJson(this T obj, string filename) @@ -62,16 +60,12 @@ namespace Wabbajack.Common return JsonConvert.SerializeObject(obj, JsonSettings); } - public static T FromJson(this AbsolutePath filename, - TypeNameHandling handling = TypeNameHandling.All, - TypeNameAssemblyFormatHandling format = TypeNameAssemblyFormatHandling.Full) + public static T FromJson(this AbsolutePath filename) { return JsonConvert.DeserializeObject(filename.ReadAllText(), JsonSettings)!; } - public static T FromJsonString(this string data, - TypeNameHandling handling = TypeNameHandling.Objects, - TypeNameAssemblyFormatHandling format = TypeNameAssemblyFormatHandling.Full) + public static T FromJsonString(this string data) { return JsonConvert.DeserializeObject(data, JsonSettings)!; } @@ -116,7 +110,7 @@ namespace Wabbajack.Common } } - private class AbolutePathConverter : JsonConverter + private class AbsolutePathConverter : JsonConverter { public override void WriteJson(JsonWriter writer, AbsolutePath value, JsonSerializer serializer) { @@ -246,11 +240,11 @@ namespace Wabbajack.Common { private static Dictionary _nameToType = new Dictionary(); private static Dictionary _typeToName = new Dictionary(); - private static bool _inited = false; + private static bool _init; public JsonNameSerializationBinder() { - if (_inited) + if (_init) return; var customDisplayNameTypes = @@ -280,7 +274,7 @@ namespace Wabbajack.Common _typeToName = _nameToType.ToDictionary( t => t.Value, t => t.Key); - _inited = true; + _init = true; } From db293b680856f9ac454a75f7a635059aa5e99da1 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sun, 12 Apr 2020 13:18:08 -0500 Subject: [PATCH 19/23] Add swapped to SetTo --- Wabbajack.Lib/AInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wabbajack.Lib/AInstaller.cs b/Wabbajack.Lib/AInstaller.cs index 6bab79b4..b0cd0536 100644 --- a/Wabbajack.Lib/AInstaller.cs +++ b/Wabbajack.Lib/AInstaller.cs @@ -282,7 +282,7 @@ namespace Wabbajack.Lib var hashResults = await DownloadFolder.EnumerateFiles() .Where(e => e.Extension != Consts.HashFileExtension) .PMap(Queue, async e => (await e.FileHashCachedAsync(), e)); - HashedArchives.Add(hashResults + HashedArchives.SetTo(hashResults .OrderByDescending(e => e.Item2.LastModified) .GroupBy(e => e.Item1) .Select(e => e.First()) From e85f6b54ddfae1b1842c86356c9891e182aaecc7 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sun, 12 Apr 2020 13:55:59 -0500 Subject: [PATCH 20/23] Clearing jobs create new lists instead of clearing Other users may have grabbed them and then have the content swiped out from under them --- Wabbajack.Lib/ACompiler.cs | 6 +++--- Wabbajack.Lib/MO2Compiler.cs | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Wabbajack.Lib/ACompiler.cs b/Wabbajack.Lib/ACompiler.cs index 06654835..45f2d445 100644 --- a/Wabbajack.Lib/ACompiler.cs +++ b/Wabbajack.Lib/ACompiler.cs @@ -42,9 +42,9 @@ namespace Wabbajack.Lib public bool IgnoreMissingFiles { get; set; } - public readonly List SelectedArchives = new List(); - public readonly List InstallDirectives = new List(); - public readonly List AllFiles = new List(); + public List SelectedArchives { get; protected set; } = new List(); + public List InstallDirectives { get; protected set; } = new List(); + public List AllFiles { get; protected set; } = new List(); public ModList ModList = new ModList(); public List IndexedArchives = new List(); diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index e79ea68a..69b1546b 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -53,7 +53,7 @@ namespace Wabbajack.Lib public AbsolutePath MO2ProfileDir => MO2Folder.Combine("profiles", MO2Profile); - public ConcurrentBag ExtraFiles { get; } = new ConcurrentBag(); + public ConcurrentBag ExtraFiles { get; private set; } = new ConcurrentBag(); public Dictionary ModInis { get; } = new Dictionary(); public HashSet SelectedProfiles { get; set; } = new HashSet(); @@ -409,10 +409,10 @@ namespace Wabbajack.Lib ///
private void ResetMembers() { - AllFiles.Clear(); - InstallDirectives.Clear(); - SelectedArchives.Clear(); - ExtraFiles.Clear(); + AllFiles = new List(); + InstallDirectives = new List(); + SelectedArchives = new List(); + ExtraFiles = new ConcurrentBag(); } /// From c4cce4739958f2a3f2d098121aed01e18d020ec2 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sun, 12 Apr 2020 14:35:17 -0500 Subject: [PATCH 21/23] Swapped calls to intended TryGet variants --- Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs | 2 +- Wabbajack.Common/GameMetaData.cs | 4 ++-- Wabbajack.Common/Json.cs | 2 +- Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs | 2 +- Wabbajack.Lib/MO2Installer.cs | 2 +- Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs | 2 +- Wabbajack.Lib/VortexInstaller.cs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs b/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs index 71b76dd4..f3012cd5 100644 --- a/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs +++ b/Wabbajack.BuildServer/Models/Jobs/EnqueueAllGameFiles.cs @@ -21,7 +21,7 @@ namespace Wabbajack.BuildServer.Models.Jobs { Utils.Log($"Indexing game files"); var states = GameRegistry.Games.Values - .Where(game => game.GameLocation() != null && game.MainExecutable != null) + .Where(game => game.TryGetGameLocation() != null && game.MainExecutable != null) .SelectMany(game => game.GameLocation().EnumerateFiles() .Select(file => new GameFileSourceDownloader.State(game.InstalledVersion) { diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index 4f8a7a67..72f2b751 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -85,7 +85,7 @@ namespace Wabbajack.Common { get { - AbsolutePath? gameLoc = GameLocation(); + AbsolutePath? gameLoc = TryGetGameLocation(); if (gameLoc == null) throw new GameNotInstalledException(this); if (MainExecutable == null) @@ -95,7 +95,7 @@ namespace Wabbajack.Common } } - public bool IsInstalled => GameLocation() != null; + public bool IsInstalled => TryGetGameLocation() != null; public string? MainExecutable { get; internal set; } diff --git a/Wabbajack.Common/Json.cs b/Wabbajack.Common/Json.cs index e846a20f..6a0af4e5 100644 --- a/Wabbajack.Common/Json.cs +++ b/Wabbajack.Common/Json.cs @@ -226,7 +226,7 @@ namespace Wabbajack.Common return (Game)i; } - GameMetaData? game = GameRegistry.GetByFuzzyName(str); + GameMetaData? game = GameRegistry.TryGetByFuzzyName(str); if (game == null) { throw new ArgumentException($"Could not convert {str} to a Game type."); diff --git a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs index b8dbdceb..0bcf896f 100644 --- a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs @@ -17,7 +17,7 @@ namespace Wabbajack.Lib.Downloaders if (gameName == null || gameFile == null) return null; - var game = GameRegistry.GetByFuzzyName(gameName); + var game = GameRegistry.TryGetByFuzzyName(gameName); if (game == null) return null; var path = game.TryGetGameLocation(); diff --git a/Wabbajack.Lib/MO2Installer.cs b/Wabbajack.Lib/MO2Installer.cs index 6ca32b01..f0647c37 100644 --- a/Wabbajack.Lib/MO2Installer.cs +++ b/Wabbajack.Lib/MO2Installer.cs @@ -55,7 +55,7 @@ namespace Wabbajack.Lib Queue.SetActiveThreadsObservable(ConstructDynamicNumThreads(await RecommendQueueSize())); if (GameFolder == null) - GameFolder = Game.GameLocation(); + GameFolder = Game.TryGetGameLocation(); if (GameFolder == null) { diff --git a/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs b/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs index 1732a4f9..7a9a5a50 100644 --- a/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs +++ b/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs @@ -26,7 +26,7 @@ namespace Wabbajack.Lib.NexusApi { var parts = link.Uri.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries); - var foundGame = GameRegistry.GetByFuzzyName(parts[0]); + var foundGame = GameRegistry.TryGetByFuzzyName(parts[0]); if (foundGame == null) { game = Game.Oblivion; diff --git a/Wabbajack.Lib/VortexInstaller.cs b/Wabbajack.Lib/VortexInstaller.cs index dd0ad998..7876097d 100644 --- a/Wabbajack.Lib/VortexInstaller.cs +++ b/Wabbajack.Lib/VortexInstaller.cs @@ -124,7 +124,7 @@ namespace Wabbajack.Lib var manualFilesDir = OutputFolder.Combine(Consts.ManualGameFilesDir); - var gameFolder = GameInfo.GameLocation(); + var gameFolder = GameInfo.TryGetGameLocation(); Info($"Copying files from {manualFilesDir} " + $"to the game folder at {gameFolder}"); From cf765942e1cce480ab33281c2fdf0a2a819b8038 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sun, 12 Apr 2020 14:47:28 -0500 Subject: [PATCH 22/23] TryGet variants /w out parameter --- Wabbajack.Common/GameMetaData.cs | 27 ++++++++++++++++--- Wabbajack.Common/Json.cs | 3 +-- .../Downloaders/GameFileSourceDownloader.cs | 3 +-- Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs | 3 +-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index 72f2b751..9268e74f 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Alphaleonis.Win32.Filesystem; using Microsoft.Win32; @@ -85,13 +86,12 @@ namespace Wabbajack.Common { get { - AbsolutePath? gameLoc = TryGetGameLocation(); - if (gameLoc == null) + if (!TryGetGameLocation(out var gameLoc)) throw new GameNotInstalledException(this); if (MainExecutable == null) throw new NotImplementedException(); - return FileVersionInfo.GetVersionInfo((string)gameLoc.Value.Combine(MainExecutable)).ProductVersion; + return FileVersionInfo.GetVersionInfo((string)gameLoc.Combine(MainExecutable)).ProductVersion; } } @@ -104,6 +104,21 @@ namespace Wabbajack.Common return Consts.TestMode ? AbsolutePath.GetCurrentDirectory() : StoreHandler.Instance.TryGetGamePath(Game); } + public bool TryGetGameLocation(out AbsolutePath path) + { + var ret = TryGetGameLocation(); + if (ret != null) + { + path = ret.Value; + return true; + } + else + { + path = default; + return false; + } + } + public AbsolutePath GameLocation() { var ret = TryGetGameLocation(); @@ -189,6 +204,12 @@ namespace Wabbajack.Common return int.TryParse(someName, out int id) ? GetBySteamID(id) : null; } + public static bool TryGetByFuzzyName(string someName, [MaybeNullWhen(false)] out GameMetaData gameMetaData) + { + gameMetaData = TryGetByFuzzyName(someName); + return gameMetaData != null; + } + public static IReadOnlyDictionary Games = new Dictionary { { diff --git a/Wabbajack.Common/Json.cs b/Wabbajack.Common/Json.cs index 6a0af4e5..d9b755cc 100644 --- a/Wabbajack.Common/Json.cs +++ b/Wabbajack.Common/Json.cs @@ -226,8 +226,7 @@ namespace Wabbajack.Common return (Game)i; } - GameMetaData? game = GameRegistry.TryGetByFuzzyName(str); - if (game == null) + if (!GameRegistry.TryGetByFuzzyName(str, out var game)) { throw new ArgumentException($"Could not convert {str} to a Game type."); } diff --git a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs index 0bcf896f..4268033e 100644 --- a/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GameFileSourceDownloader.cs @@ -17,8 +17,7 @@ namespace Wabbajack.Lib.Downloaders if (gameName == null || gameFile == null) return null; - var game = GameRegistry.TryGetByFuzzyName(gameName); - if (game == null) return null; + if (!GameRegistry.TryGetByFuzzyName(gameName, out var game)) return null; var path = game.TryGetGameLocation(); var filePath = path?.Combine(gameFile); diff --git a/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs b/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs index 7a9a5a50..f2f4c98c 100644 --- a/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs +++ b/Wabbajack.Lib/NexusApi/NexusUpdatesFeeds.cs @@ -26,8 +26,7 @@ namespace Wabbajack.Lib.NexusApi { var parts = link.Uri.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries); - var foundGame = GameRegistry.TryGetByFuzzyName(parts[0]); - if (foundGame == null) + if (!GameRegistry.TryGetByFuzzyName(parts[0], out var foundGame)) { game = Game.Oblivion; modId = 0; From 89d8c75956b913ec49bbf891f5c5c86e55ad9be5 Mon Sep 17 00:00:00 2001 From: JD Smith Date: Mon, 13 Apr 2020 12:58:08 -0500 Subject: [PATCH 23/23] add enderal as a recognized game --- Wabbajack.Common/GameMetaData.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index 9268e74f..7e25ff30 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -21,6 +21,7 @@ namespace Wabbajack.Common FalloutNewVegas, [Description("Skyrim Legendary Edition")] Skyrim, + Enderal, [Description("Skyrim Special Edition")] SkyrimSpecialEdition, [Description("Fallout 4")] @@ -533,6 +534,22 @@ namespace Wabbajack.Common "Stardew Valley.exe" } } + }, + { + Game.Enderal, new GameMetaData + { + SupportedModManager = ModManager.MO2, + Game = Game.Enderal, + NexusName = "enderal", + MO2Name = "Enderal", + MO2ArchiveName = "enderal", + SteamIDs = new List{1027920}, + RequiredFiles = new List + { + "TESV.exe" + }, + MainExecutable = "TESV.exe" + } } };