From 4e1a32caac37ee7b1160b3ca628b6491f8dbd5be Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 9 Apr 2020 16:05:07 -0500 Subject: [PATCH] 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; - } } }